IOS Development Series-Objective-C memory management (written by the predecessors, for reference, awesome)

Source: Internet
Author: User

IOS Development Series-Objective-C memory management (written by the predecessors, for reference, awesome)
Overview

We know that a large number of objects need to be created during the program running. Similar to other advanced languages, objects in ObjC are stored in the heap, the system does not automatically release the memory in the heap (note that the basic types are managed by the system and placed on the stack ). If an object is not promptly released after it is created and used, it will occupy a large amount of memory. Other advanced languages such as C # and Java solve this problem through garbage collection (GC), but there is no similar garbage collection mechanism in OjbC, therefore, the memory management needs to be manually maintained by developers. Today we will focus on ObjC memory management:

  1. Reference Counter
  2. Attribute Parameters
  3. Automatically release the pool Reference Counter

    In Xcode4.2 and later versions, due to the introduction of the ARC (Automatic Reference Counting) mechanism, Xcode can automatically add memory release code to your code during program compilation, if you compile Xcode to manually release the code, an error is returned. Therefore, if you are using Versions later than Xcode4.2 in today's content (I believe most of your friends are using a higher version than this one ), you must manually disable ARC to understand the memory recycle mechanism of ObjC.

    The memory management mechanism in ObjC is equally important to the pointer content in C language. It is not difficult to develop a program, but excellent programs are more important than memory management, which usually occupy less memory, run more smoothly. Although ARC is introduced in the new version of Xcode, it often cannot completely solve your problem. Close ARC in Xcode: Project properties-Build Settings -- search for "garbage" and find Objective-C Automatic IC Reference Counting to No.

    Memory Management Principle

    We all know that GC is automatically managing the memory in C # And Java. when an object is instantiated, a variable is usually used to reference this object (the object address is stored in the variable ), when the referenced variable is no longer used (that is, the object is no longer referenced), GC automatically recycles the object, Simply put: when an object is referenced without any variables, it is recycled.

    For example, the following C # code snippet

    using System;namespace GC{    class Program    {        private static void Test()        {            object o=new object();        }        static void Main(string[] args)        {            Test();        }    }}

    The above is a piece of C # code. In the Test () method, an Object is created through new Object (), and o is an Object reference (storing the Object address ), it is a local variable within the Test () method.

    After the Test () method is executed, o will be released. At this time, because no variable is referencing the new Object (), GC will automatically recycle the space occupied by this Object.

    But there is no garbage collection mechanism in ObjC, so how does the memory in ObjC be managed? In fact, in ObjC, memory management relies on Object Reference counters: In ObjC, each object has a corresponding INTEGER (retainCount), which is called "reference counter ", when an object is created, its reference counter is 1, when the alloc, retain, new, and copy methods of this object are called, the reference counter automatically adds 1 to the original base (the method for calling an object in ObjC is to send a message to this object ), when the release method of this object is called, its reference counter minus 1. If the reference counter of an object is 0, the system will automatically call the dealloc method of this object to destroy this object.

    The following is a simple example to illustrate the knowledge of referencing a counter:

    Person. h

    /// Person. h // MemoryManage /// Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    @ Interface Person: NSObject # pragma mark-attribute @ property (nonatomic, copy) NSString * name; @ property (nonatomic, assign) int age; @ end
       

    Person. m

    /// Person. m // MemoryManage /// Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import Person. h @ implementation Person # pragma mark-override method # pragma mark rewrite dealloc method. In this method, objects are usually released-(void) dealloc {NSLog (@ Invoke Person's dealloc method .); [super dealloc]; // note that the dealloc method of the parent class must be called at the end (two purposes: one is that the parent class may have other referenced objects to be released; the other is: the current object is actually released in the super dealloc)} @ end

    Main. m

    //// Main. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    # Import Person. hvoid Test1 () {Person * p = [[Person alloc] init]; // call alloc and reference counter + 1 p. name = @ Kenshin; p. age = 28; NSLog (@ retainCount = % lu, [p retainCount]); // result: retainCount = 1 [p release]; // result: invoke Person's dealloc method. // if the release method is called above, the object pointed to by p will be destroyed, but the address of the Person object is also stored in Variable p. // If p = nil is not set, p is a wild pointer, and the memory it points to does not belong to this program. Therefore, it is very dangerous to p = nil; // If p = nil is not set, if you call the object release again, an error will be reported, but if p is already a null pointer, // [p release] will not be reported if you send a message to the NULL pointer in ObjC;} void Test2 () {Person * p = [[Person alloc] init]; p. name = @ Kenshin; p. age = 28; NSLog (@ retainCount = % lu, [p retainCount]); // result: retainCount = 1 [p retain]; // reference counter + 1 NSLog (@ retainCount = % lu, [p retainCount]); // result: retainCount = 2 [p release]; // call 1 release reference counter-1 NSLog (@ retainCount = % lu, [p retainCount]); // result: retainCount = 1 [p release]; // result: invoke Person's dealloc method. p = nil;} int main (int argc, const char * argv []) {@ autoreleasepool {Test1 () ;}return 0 ;}
       

    In the above code, we can use the dealloc method to check whether an object has been recycled. If not, memory leakage may occur. If an object is released, we manually set the variable that references it to nil. Otherwise, a wild pointer error may occur, in addition, it should be noted that sending messages to null objects in ObjC will not cause errors.

    The format of a wild pointer error is usually shown in Xcode:Thread 1: EXC_BAD_ACCESS (code = exc_i1__gpflt)Error. Because you have accessed a piece of memory that does not belong to you.

    Memory release Principle

    Manual memory management is sometimes not easy, because object reference is sometimes complicated, and objects may cross-reference each other. In this case, a rule should be followed:Who created and released.

    Assume that there is a Person class, and each Person may buy a Car. In general, we may extract a method to buy a Car separately, at the same time, when buying a car, we may look at several more cars to determine the desired car. Our code is as follows:

    Car. h

    //// Car. h // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    @ Interface Car: NSObject # pragma mark-attribute # pragma mark license plate number @ property (nonatomic, copy) NSString * no; # pragma mark-public method # pragma mark running method-(void) run; @ end
       

    Car. m

    //// Car. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import Car. h @ implementation Car # pragma mark-public method # pragma mark running method-(void) run {NSLog (@ Car (% @) run ., self. no) ;}# pragma mark-override method # pragma mark override dealloc method-(void) dealloc {NSLog (@ Invoke Car (% @) dealloc method ., self. no); [super dealloc] ;}@ end

    Person. h

    /// Person. h // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    @ Class Car; @ interface Person: NSObject {Car * _ car;} # pragma mark-attribute # pragma mark name @ property (nonatomic, copy) NSString * name; # pragma mark-public method # set Method Of The pragma mark Car Attribute-(void) setCar :( Car *) car; # get method of The pragma mark Car Attribute-(Car *) car; @ end
       

    Person. m

    /// Person. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import Person. h # import Car. h @ implementation Person # pragma mark-public method # set Method Of The pragma mark Car Attribute-(void) setCar :( Car *) car {if (_ car! = Car) {// first, determine whether the variable to be assigned is the same as the current member variable [_ car release]; // release the previous object _ car = [car retain]; // retain }}# get method of The pragma mark Car Attribute-(Car *) car {return _ car ;} # pragma mark-override method # pragma mark override dealloc method-(void) dealloc {NSLog (@ Invoke Person (% @) dealloc method ., self. name); [_ car release]; // release the object here, even if no value has been assigned due to a null pointer, there will be no error [super dealloc];} @ end

    Main. m

    //// Main. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    # Import Person. h # import Car. hvoid getCar (Person * p) {Car * car1 = [[Car alloc] init]; car1.no = @ 888888; p. car = car1; NSLog (@ retainCount (p) = % lu, [p retainCount]); Car * car2 = [[Car alloc] init]; car2.no = @ 666666; [car1 release]; car1 = nil; [car2 release]; car2 = nil;} int main (int argc, const char * argv []) {@ autoreleasepool {Person * p = [[Person alloc] init]; p. name = @ Kenshin; getCar (p); [p. car run]; [p release]; p = nil;} return 0 ;}
       

    Program running result:

    According to the running results, the three objects p, car1, and car2 have been recycled, and [p. car run] can run smoothly, which has already met our needs. But here we need to explain the implementation of the setCar method. Why is the setCar method not written as follows:

    -(void)setCar:(Car *)car{    _car=car;}

    Didn't we use this method when talking about attribute definitions?

    According to the memory release principle mentioned above, the getCar method is completely consistent. The two objects car1 and car2 defined in this method are also released in this method, p objects in the main function are also defined and released in the main function. However, if you find that the call to the getCar method is followed by the call to the car's run method, of course, this should be a general design in the Process of program design and development. If setCar is written as "_ car = car", after the getCar method is called, the person's car attribute is released, an error is reported when you call the run method (you can try it yourself ). However, the following method does not solve the problem:

    -(Void) setCar :( Car *) car {if (_ car! = Car) {// first, determine whether the variable to be assigned is the same as the current member variable [_ car release]; // release the previous object _ car = [car retain]; // retain again when assigning values }}

    In this method, we use [car retain] to ensure that the counter + 1 is referenced in each attribute assignment. In this way, the getCar method can be called to ensure that the car attribute of a person will not be released, to ensure the normal release of the last value assignment object (car1), we perform the release operation on the original value before the new value is added. Finally, perform a release operation on _ car in the dealloc method of Person (because a retain operation is performed in setCar) to ensure that _ car can be recycled normally.

    Attribute Parameters

    There are many cases of writing the setCar method like above. How can I use @ property for automatic implementation? The answer is to use Attribute parameters. For example, the setter method of the car attribute above can be defined as follows through @ property:

    @property (nonatomic,retain) Car *car;

    You will find that at this moment we do not have to manually implement the getter and setter method programs of car, but the memory is still not leaked. In fact, we should have already seen that we also added the (nonatomic, copy) parameters when defining the name attribute of Person. What do these parameters mean?

    VcGVydHlQYXJhbWV0ZXI = "border =" 0 "height =" 161 "src =" http://www.bkjia.com/uploads/allimg/150903/0425243003-2.png "title =" propertyParameter "width =" 642 "/>

    @ Property parameters can be divided into three types, that is, up to three parameters can be separated by commas (,). You can select one of the three types of parameters in the preceding table. If you do not set or set only one type of parameters, the program uses each of the default parameters in the three types. default parameters: (atomic, readwrite, assign)

    Under normal circumstances, if one attribute in multi-threaded development may be accessed by two or more threads at the same time, you can consider the atomic attribute. Otherwise, nonatomic is recommended, without locking, which is more efficient; the readwirte method generates the getter and setter methods. If readonly is used, only the getter method is generated. For details about how to process the set method, Let's define a property, three code generation methods are listed here:

    Assign for basic data types

    -(void)setA:(int)a{    _a=a;}

    Retain, usually used for non-string objects

    -(void)setA:(Car *)a{    if(_a!=a){        [_a release];        _a=[a retain];    }}

    Copy, usually used for string objects

    -(void)setA:(NSString *)a{    if(_a!=a){        [_a release];        _a=[a copy];    }}
    Auto Release pool

    In ObjC, there is also a mechanism for automatic memory release called "automatic reference count" (or "automatic release pool"). Unlike C # and Java, this is only a semi-automatic mechanism, and some operations still need to be set manually. The @ autoreleasepool keyword is used to declare a code block for automatic memory release. If an object calls the autorelase method during initialization, after the code block is executed, objects that call the autorelease method in a block will automatically call the release method once. In this way, automatic release is enabled, and the object destruction process is also delayed (the release method is called uniformly ). See the following code:

    Person. h

    /// Person. h // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    @ Interface Person: NSObject # pragma mark-attribute # pragma mark name @ property (nonatomic, copy) NSString * name; # pragma mark-common method # pragma mark constructor with parameters-(Person *) initWithName :( NSString *) name; # pragma mark gets an object (static method) + (Person *) personWithName :( NSString *) name; @ end
       

    Person. m

    /// Person. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import Person. h @ implementation Person # pragma mark-public method # pragma mark constructor with parameters-(Person *) initWithName :( NSString *) name {if (self = [super init]) {self. name = name;} return self;} # pragma mark gets an object (static method) + (Person *) personWithName :( NSString *) name {Person * p = [[Person alloc] initWithName: name] autorelease]; // note that autorelease return p is called here ;} # pragma mark-override method # pragma mark override dealloc method-(void) dealloc {NSLog (@ Invoke Person (% @) dealloc method ., self. name); [super dealloc] ;}@ end

    Main. m

    //// Main. m // MemoryManage /// Created by Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import
       
        
    # Import Person. hint main (int argc, const char * argv []) {@ autoreleasepool {Person * person1 = [[Person alloc] init]; [person1 autorelease]; // After the autorelease method is called, you do not need to manually call the release method. person1.name = @ Kenshin; // because autorelease is delayed, so here we can still use person1 Person * person2 = [[[Person alloc] initWithName: @ Kaoru] autorelease]; // call the autorelease method Person * person3 = [Person personWithName: @ rosa]; // autorelease has been called internally, so you do not need to manually release it. This also complies with the memory management principle, because there is no alloc, release or autorelease Person * person4 = [Person personWithName: @ jack]; [person4 retain];}/* result: Invoke Person (rosa) dealloc method. invoke Person (Kaoru) dealloc method. invoke Person (Kenshin) dealloc method. */return 0 ;}
       

    After the preceding @ autoreleaespool code block is executed, all three objects are released, but person4 is not released. The reason is very simple because we retained it once manually, after the Auto release pool is released, the four pairs of release methods are called. After the release of person4 is called, its reference counter is 1, and none of them are released. (This is an inverse example, will cause memory leakage); The autorelase method delays the release of the memory of an object until the automatic release pool is destroyed. Therefore, the above person1 still exists after autorelase is called, therefore, assigning a value to the name will not cause any problem. In ObjC, if a static method returns an object, we need to call the autorelease method in the static method, because according to the memory release principle, if you do not perform the alloc operation during external use, you do not need to call release or autorelase again. Therefore, this operation must be completed within the static method.

    A brief summary of automatic memory release:

    1. The autorelease method does not change the reference counter of an object, but places the object in the Auto Release pool;
    2. The essence of the automatic release pool is that when the automatic release pool is destroyed, the release method of the object is called, and the object cannot be destroyed unless the reference counter of an object is greater than 1 );
    3. Because the automatic release pool finally destroys objects in a unified manner, if an operation occupies more memory (more objects or more resources are occupied by objects ), it is best not to place it in the Auto Release pool or consider putting it in multiple Auto Release pools;
    4. Static Methods in the class library in ObjC generally do not need to be manually released. The autorelease method has been called internally. Author: Cui jiangtao (KenshinCui) Original Source:

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.