IOS Development Series-Objective-C memory management, iosobjective-c

Source: Internet
Author: User

IOS Development Series-Objective-C memory management, iosobjective-c
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:

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 <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 (because the parent class method may also have corresponding objects to be destroyed)} @ 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 .} int main (int argc, const char * argv []) {@ autoreleasepool {Test1 (); Test2 ();} 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]; [car2 release];} int main (int argc, const char * argv []) {@ autoreleasepool {Person * p = [[Person alloc] init]; p. name = @ "Kenshin"; getCar (p); [p. car run]; [p release];} 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?

@ 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: (nonatomic, 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 <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 again. Therefore, this operation must be completed within the static method.

A brief summary of automatic memory release:


Ios development requires more memory management

Memory Management is an independent chapter in the early OC development textbooks, showing its importance.
However, with the emergence of ARC, the difficulty of Memory Management Code is reduced.

Therefore, if a developed product uses a relatively high version,
The landlord can ignore the memory management burden caused by code.

Summary of Objective-c memory overflow experience, sharing with others

The memory of iOS platform uses the reference counting mechanism and introduces the semi-automatic release mechanism, as a result, developers are very prone to memory leakage and inexplicable memory growth in terms of memory usage. This article will introduce the memory usage principles and usage traps of the iOS platform, and deeply analyze the autorelease mechanism; the process of handling low-memory alarms, and introduces the trace records of memory surges and the usage of related tools based on your instance;
IOS platform memory FAQ
As a developer of iOS platform, have you ever been troubled by memory problems? Memory continues to grow inexplicably, crash programs, and hard-to-find memory leaks are common issues related to the memory of the iOS platform. This article will introduce the memory management mechanism of the iOS platform in detail, the autorelease mechanism and memory usage traps will solve most of the memory problems on the iOS platform and improve program stability;
1 Introduction to memory management on iOS platform
The memory management of iOS platform uses the reference counting mechanism. when an object is created using the alloc or allWithZone method, the reference counting will be + 1. When the released object uses the release method, the reference count is-1, which means that each object will track the number of other objects that reference it. Once the reference count is 0, the memory of the object will be released. In addition, iOS also provides a latency release mechanism, AutoRelease, to apply for memory in this way, developers do not need to manually release, the system will release the memory at a certain time; due to the diversity of memory management on the iOS platform, developers are prone to memory leaks or program crashes during memory usage, this article will introduce in detail the usage specifications and technical skills of iOS platform memory and how to use tools to avoid or discover problems;
2 iOS platform memory usage principles
2.1 object ownership and destruction
2.1.1 Who created and released;
If the object is created using alloc, new, copy, and mutableCopy, you must call the release or autorelease method to release the memory;
If it is not released, the memory will leak!
2.1.2 who retain and who releases;
If a retain message is sent to an object, the reference count will be greater than 1, the release or autorelease method must be sent after use to release the memory or restore the reference count;
If it is not released, the memory will leak!
2.1.3 not created and retain not released;
Do not release objects that are not alloc or retain, otherwise the program will crash;
Do not release the autorelease object, otherwise the program will crash;
2.2 object deep copy and shortest copy
Generally, copying an object includes creating a new instance and initializing the instance with the value in the original object. Copying a non-pointer instance variable is simple, such as Boolean, integer, and floating point. There are two methods to copy the instance variables. A method is called shortest copy, which copies the pointer value of the original object to the copy. Therefore, the original object and the copy share the reference data. Another method is deep copy, that is, copy the data referenced by the pointer and assign it to the instance variable of the copy.
2.2.1 deep copy
In the deep copy process, a new object is created and the reference count is 1. The new object is initialized with the value of the old object;
ClassA * objA = [[ClassA alloc] init];
ClassA * objB = [objA copy];
ObjB is a new object with a reference count of 1, and the objB data is equivalent to the objA data;
Note: The objB needs to be released, otherwise it will cause memory leakage!
2.2.2 shallow copy
The process of copying objects is to add the reference count of the original object + 1 without introducing new objects.
ClassA * objA = [[ClassA alloc] init];
ClassA * objB = [objA retain];
Note: The objB must be released to restore the reference count of objA. Otherwise, memory leakage will occur!
2.3 object access method 2.3.1 attribute declaration ...... remaining full text>

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.