IOS study notes -- Objective-C memory management, ios -- objective-c

Source: Internet
Author: User

IOS study notes -- Objective-C memory management, ios -- objective-c

By KenshinCui, 17317 read, 6 comments, favorites, Edit

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 heap memory (note that the basic type is 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 :( original address: http://www.cnblogs.com/kenshincui/p/3870325.html)

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 use Versions later than Xcode4.2 in today's content (I believe most of your friends use 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 cannot solve your problem in many cases. 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 ), after 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.

/// Person. h // MemoryManage /// Kenshin Cui on 14-2-15. // Copyright (c) 2014 Kenshin Cui. all rights reserved. // # import <Foundation/Foundation. h> @ 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 <Foundation/Foundation. h> # import "Person. h "void 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 <Foundation/Foundation. h> @ 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 <Foundation/Foundation. h> @ 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 <Foundation/Foundation. h> # import "Person. h "# import" Car. h "void 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:

-(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 including 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 assigned 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?

-(Void) setA :( int) 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. Automatic Memory release uses the @ autoreleasepool keyword to declare a code block. 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 <Foundation/Foundation. h> @ 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 <Foundation/Foundation. h> # import "Person. h "int 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 release it manually. 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. Therefore, this operation must be performed inside the static method.

A brief summary of automatic memory release:

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.