iOS memory management mechanism

Source: Internet
Author: User

Overview

We know that in the process of running the program to create a large number of objects, similar to other high-level languages, in the ObjC object when stored in the heap, the system does not automatically free the memory in the heap (note that the basic type is managed by the system itself, on the stack). If an object is created and used without being released in a timely manner then it consumes a lot of memory. Other high-level languages such as C #, Java are addressed by garbage collection (GC), but there is no similar garbage collection mechanism in OJBC, so its memory management needs to be manually maintained by the developer. Today will focus on OBJC memory management:

    1. Reference counter
    2. Property parameters
    3. Auto Free Pool
Reference counter

In Xcode4.2 and later versions, because of the introduction of the arc (Automatic Reference counting) mechanism, Xcode can automatically add the memory release code to your code when the program is compiled, and if you write a manual release code, Xcode will error, So in today's content if you're using a post-Xcode4.2 version (believe that most of your friends now have a higher version than this), you have to manually turn off arc, which will help you understand the OBJC memory recovery mechanism.

The memory management mechanism in OBJC is just as important as the content of pointers in C, and it is not difficult to develop a program, but good programs weigh more heavily on memory management, which often consumes less memory and runs more smoothly. Although the new version of Xcode introduces Arc, many times it does not completely solve your problem. Turn off arc in Xcode: Project Properties-build settings--Search "garbage" to find objective-c Automatic Reference counting set to No.

Principles of memory management

We all know that in C #, Java has a GC in the automatic management of memory, when we instantiate an object will usually have a variable to refer to this object (the variable store object address), when the reference variable is no longer used (that is, no longer refer to the object), the GC will automatically reclaim this object, Simply put: When an object does not have any variable references, it is recycled.

For example, the following C # code fragment

Using System;namespace gc{    class program    {        private static void Test ()        {            Object O=new object ();        }        static void Main (string[] args)        {            Test ();}}    }

The above is a C # code, in the test () method, the object is created by the new object, O is a reference to an object (the address of the object is stored), it is a local variable, scoped to the test () method inside.

When the test () method is executed, O is freed and the GC automatically reclaims the space occupied by the object because there is no variable referencing the object "new object".

But there is no garbage collection mechanism in OBJC, so how is memory managed in OBJC? In fact, in OBJC memory management is dependent on the object reference counter to do: In ObjC each object has a corresponding integer (retaincount), called "Reference counter", when an object is created after its reference counter is 1, when the object is called the Alloc, Retain, new, copy method after the reference counter automatically add 1 on the original (OBJC call an object method is to send a message to this object), when the release method called this object its reference counter minus 1, if an object reference counter is 0, The system automatically calls the object's Dealloc method to destroy the object.

The following is a simple example of the knowledge of reference counters:

Person.h

  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 Overrides Dealloc method, In this method, the object release operation is usually performed-(void) dealloc{    NSLog (@ "Invoke person ' s Dealloc method.");    [Super dealloc];//Note Finally, be sure to call the Dealloc method of the parent class (two purposes: one is that the parent class may have other reference objects that need to be freed, and two: the actual release of the current object is done in 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, reference counter +1 [email protected] "Kenshin";        p.age=28;    NSLog (@ "Retaincount=%lu", [P retaincount]);    Results: Retaincount=1 [P release];                Result: Invoke person ' s Dealloc method.    Above called the release method, p point to the object will be destroyed, but at this time the variable p also holds the address of the person object,//If not set P=nil, then P is a wild pointer, it points to the memory is not part of this program, it is very dangerous p=nil; If you do not set the P=nil, at this time if the call object release will be an error, but if the p is already a null pointer,//in the OBJC to send a message to the null pointer will not error [P release];}    void Test2 () {person *p=[[person alloc]init];    [email protected] "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];//calls 1 times release reference counter-1 NSLog (@ "Retaincount=%lu", [P retaincOunt]);    Results: 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 code above, we can see if an object has been reclaimed by the Dealloc method, and if it is not recycled, it may cause a memory leak. If an object is freed, then the last variable that references it is set to nil manually, otherwise it may cause a wild pointer error, and it is important to note that sending a message to an empty object in OBJC does not cause an error.

The Wild pointer error form in Xcode usually behaves as:Thread 1:exc_bad_access (code=exc_i386_gpflt) error. Because you have access to a piece of memory that is not yours.

Principles of Memory release

Manually managing memory is sometimes not easy, because object references are sometimes convoluted, and objects may cross-reference each other, and a rule is followed: who creates, who releases .

Suppose that there is now a person class, and that everyone may buy a car, and usually buy a car, we may be able to take a single method, while buying a car we may see a few more to finalize the ideal car, now 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 plate number @p Roperty (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 Run Method-(void) run{    NSLog (@ "Car (%@) run. ", self.no);} #pragma mark-Overwrite method #pragma mark overrides the Dealloc method-(void) dealloc{        NSLog (@ "Invoke Car (%@) dealloc", 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 #pragma the set method of the Mark car Property-(Voi d) Setcar: (car *) car; #pragma  The Get method of the Mark Car Property-(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 #pragma mark The set method of the car Property-(void) Setcar: (Car *) car{    if (_car!=car) {//First determine if the variable to be assigned is the same variable as the current member variable        [_car release];//Release the previous object        _car=[car retain];//retain}} when assigning values    #pragma  The Get method of the Mark car Property-(Car *) car{    return _car;} #pragma mark-Overwrite method #pragma mark overrides the Dealloc method-(void) dealloc{    NSLog (@ "Invoke person (%@) dealloc", self.name);    [_car release];//frees objects here, even if they are not assigned, because null pointers do not go wrong    [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];    [Email protected] "888888";        P.CAR=CAR1;        NSLog (@ "Retaincount (p) =%lu", [P retaincount]);        Car *car2=[[car Alloc]init];    [Email protected] "666666";        [Car1 release];    Car1=nil;        [Car2 release];    Car2=nil;} int main (int argc, const char * argv[]) {    @autoreleasepool {person        *p=[[person alloc]init];        [Email protected] "Kenshin";                Getcar (p);                [P.car run];                [P release];                P=nil;            }    return 0;}

Program Run Result:

From the running results of the three objects created by P, CAR1, car2 are recycled, and [P.car Run] can also run smoothly, has reached our needs. But here we need to explain the implementation of the Setcar method, why the Setcar method is not written in the following form:

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

Is this the way we used to be when we talked about the definition of attributes?

According to the memory release principle mentioned earlier, the Getcar method is fully compliant, the two objects defined in this method car1, Car2 are also released in this method, including the P object in the main function is also defined and released in the main function. However, if you find that the Getcar method is called immediately after the call to the car's Run method, of course, in the program design and development process should be a more common design. If Setcar is written in the form of "_car=car", when the Getcar method is called, the car property of the person is released, and the Run method is called with an error (everyone can try it out). But there are no problems with the following ways:

-(void) Setcar: (Car *) car{    if (_car!=car) {//First determine if the variable to be assigned is the same variable as the current member variable        [_car release];//Release the previous object        _car=[ Car retain];//re-retain} when assigning value    

Because in this method we guarantee each property assignment by [car retain] When the object references counter +1, so that the Getcar method can be used to ensure that the car property is not released, and secondly, in order to ensure that the last Assignment object (CAR1) can be released normally, We release the original value before assigning a new value. Finally in the person's Dealloc method to _car a release operation (because Setcar did a retain operation) to ensure that the _car can be recovered normally.

Property parameters

The case of writing Setcar method like above is more, then how to use @property to implement automatically? The answer is to use a property parameter, such as the setter method of the car property above, which can be defined by @property as follows:

@property (Nonatomic,retain) Car *car;

You will find that we do not have to manually implement car getter, setter method program still no memory leaks. In fact, everyone should have seen the name attribute definition of the previous person when we also added the (nonatomic,copy) parameter, what exactly is the meaning of these parameters?

@property parameters are divided into three categories, that is, the parameters can be up to three, the middle is separated by commas, each type of parameter can be from the above table three types of parameters of the candidate one. If you do not set or set only one of these parameters, the program uses each default parameter in the three classes, the default parameter: (atomic,readwrite,assign)

In general, if a property in multi-threaded development may be two and more than two threads simultaneously access, at this time can consider the atomic property, otherwise it is recommended to use nonatomic, no lock, high efficiency; Readwirte method generates getter, setter two methods, If you use ReadOnly, only the Getter method is generated, and for the Set method processing you need to be specific, let's say we define an attribute a, which lists three ways to generate code:

Assign, for basic data types

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

Retain, typically used for non-string objects

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

Copy, commonly used for string objects, blocks, Nsarray, nsdictionary

-(void) SetA: (NSString *) a{    if (_a!=a) {        [_a release];        _a=[a copy];}    }

Note: This article is based on the MRC introduction, the situation under arc is different, see other articles, such as arc under the basic data type default property parameter is (Atomic,readwrite,assign), the object type default property parameter is (Atomic,readwrite, Strong)

Auto Free Pool

In OBJC, there is also a mechanism for automatic memory release called "Automatic Reference count" (or "auto-free Pool"), unlike C #, Java, this is a semi-automatic mechanism, some operations need to be set manually. Automatic memory release declares a block of code using the @autoreleasepool keyword, and if an object calls the Autorelase method at initialization time, when the code block executes, Objects that have called the Autorelease method in a block will automatically call the release method once. This has the effect of automatic release, while the object's destruction process is also delayed (Unified call release method). Look at 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-public 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's 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];//notice here called Autorelease    return p;} #pragma mark-Overwrite method #pragma mark overrides the Dealloc method-(void) dealloc{    NSLog (@ "Invoke person (%@) dealloc", 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];//calls the Autorelease method and does not need to call the release method manually [email protected] "Kenshin";// Since Autorelease is delayed release, person1 person *person2=[[[person alloc]initwithname:@ "Kaoru" can still be used here autorelease];// Call the Autorelease method person *person3=[person personwithname:@ "Rosa"];//internal has been called autorelease, so do not need to release manually, this also conforms to the memory management principle,        Because there is no alloc so there is no need to release or autorelease person *person4=[person personwithname:@ "Jack";    [Person4 retain];     }/* Results: Invoke person (rosa) Dealloc method.     Invoke person (Kaoru) Dealloc method.     Invoke person (Kenshin) Dealloc method. */return 0;} 

When the above @autoreleaespool code block is finished, the three objects are released, but Person4 is not released for simple reasons, because we manually retain once, when the automatic release of the pool released after the call four pairs of release method, When the release of Person4 is finished, its reference counter is 1, all of it is not released (this is a counter-example, which will cause memory leaks); The Autorelase method delays the memory release of an object until the automatic free pool is destroyed, so the above Person1, It also exists after the autorelase is called, so there is no problem assigning a value to name, and in OBJC it is usually necessary to call the Autorelease method in a static method if a static method returns the object itself, because in the memory release principle, When used externally, no alloc operation is required and no more calls to release or autorelase, so this operation needs to be done inside the static method.

For a simple summary of automatic memory release:

    1. The Autorelease method does not alter the object's reference counter, but simply places the object in the auto-release pool;
    2. The auto-free pool is essentially the release method that calls the object when the auto-release pool is destroyed, and does not necessarily destroy the object (for example, if the reference counter of an object is >1, it cannot be destroyed at this time);
    3. Since the auto-free pool finally uniformly destroys objects, if an operation is more memory intensive (objects are more or objects occupy more resources), it is best not to put them into the auto-release pool or consider putting them into multiple auto-release pools;
    4. The static methods in the class library in OBJC generally do not need to be released manually, and the Autorelease method is called internally.

iOS memory management mechanism

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.