Objective-C Memory Management

Source: Internet
Author: User
Statement

You are welcome to repost this article, but please respect the author's Labor achievements. repost this article and keep the statement in this box. Thank you.
Article Source: http://blog.csdn.net/iukey

This is probably because objective-C is the superset of C, so objective-C also uses alloc to apply for memory. The difference is that C calls free to directly release the memory, objective-C does not directly call dealloc to release the memory. The entire objective-C uses Object references, and each object has a reference counter. When the counter is 0, the system calls dealloc to release the memory. Objective-C provides the autorelease attribute, allowing the system to automatically release the memory occupied by objects. You can set an automatic release pool in the program. The system uses this pool to track objects. You can use the following statement to create an automatic release pool:

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc]init];

At the entrance of our program, xcode also helped us build an automatic release pool and added the entire program loop.

Int main (INT argc, char * argv []) {@ autoreleasepool {// I did not understand the truth, but I know that it has created an automatic release pool, then, we put our program into this pool and return uiapplicationmain (argc, argv, nil, nsstringfromclass ([appdelegate class]);} // Let alone the specific meaning of this, you only need to know That xcode has helped us create an automatic release pool and then put the entire program into the automatic release pool.

After the pool is automatically released, the basic framework automatically puts arrays, strings, and other pairs in the pool. When the following statement is executed, the objects in the pool are automatically released:

[ pool drain];

In short, an object is marked as an automatically released object, which is then added to the automatically released pool. In addition to using drain to release objects in the pool, all objects in the pool will be released when the pool itself is released automatically. The automatic release pool statement is as follows:

[ pool release ];

Previously, there was no Automation Reference counting function. Now, I think arc is mainly designed for programmers who are transferred from Java, because this is almost equivalent to the automatic garbage collector in Java. Most programmers who transfer data from C/C ++ are willing to release data manually, because they do not believe in the efficiency of automatic release, and they like to control everything, such as me. If you want to enable it, check this option when creating a project:

If you use manual memory management, see:

I. Applying for memory (alloc)

When using alloc to create an object, you need to release it after it is used up. You do not need to release an object set to autorelease by yourself, if you do, sorry, the program will crash.

// If str1 is autorelease, nsstring * str1 = [nsstring string] is automatically released; // str2 needs to manually release nsstring * str2 = [[nsstring alloc] init]; // [str2 release] After str2 is used;

For ease of understanding, you can understand that the autorelease object will be automatically released when it is released.

Ii. release memory (dealloc)

Before an object is deleted from the memory, the system will call the dealloc method, which is the best time to release the object member variable. For example:

- (void)dealloc{    [_window release];    [super dealloc];}

In the preceding example, call release to release the memory occupied by the member Variable _ window. Relatively speaking, using standard release is a little faster than autorelease. The last line [Super dealloc]; is very important. You must call this method to make the parent class clear about itself; otherwise, memory leakage may occur.

In Arc mode, dealloc is not called. Instead, the Finalize method must be implemented.

3. retaincout)

The entire objective-C uses Object reference, and each object has a reference counter. When an object is created using the alooc (or copy) method. The counter value is 1. When the counter is 0, the system automatically calls the dealloc method to release objects in the memory. For example:

Stu * Stu = [[STU alloc] init]; // the counter is 1 [STU retain]; // the counter is 2 [STU release]; // The counter is 1 [STU release]; // the counter is 0. After the system automatically calls the dealloc method // after the release, if any method of the object is called, the program will terminate [STU gohiking] abnormally; // crash

To prevent the above exception and crash, you can add one sentence after the last release:

 stu =nil;

The preceding statement sets this object to nil. After that, Nil is returned for any method that calls the Member, rather than terminating an exception. Let's take a look at the following example:

Int main (INT argc, char * argv []) {ngutoreleasepool * Pool = [[ngutoreleasepool alloc] init]; nsnumber * int1 = [nsnumber numberwithint: 222]; nsnumber * int2; nsmutablearray * arr1 = [nsmutablearray array]; nslog (@ "after initialization: int1 (retaincount): % lu int2 (retaincount): % lu", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); [arr1 addobject: int1]; nslog (@ "after adding int1 to an array: int1 (retaincount ): % lu int2 (retaincount): % lu ", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); int2 = int1; nslog (@ "after the value assignment operation: int1 (retaincount): % lu int2 (retaincount): % lu", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); [int1 retain]; nslog (@ "after int1 retain: int1 (retaincount): % lu int2 (retaincount): % lu", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); [int1 release]; nslog (@ "int1 release later: int1 (retaincount): % lu int2 (retaincount ): % lu ", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); [arr1 removeobject: 0]; nslog (@ "after int1 is deleted from the array: int1 (retaincount): % lu int2 (retaincount): % lu", (unsigned long) [int1 retaincount], (unsigned long) [int2 retaincount]); [pool drain]; return 0 ;}

Program result:

After initialization: int1 (retaincount): 1 int2 (retaincount): 0

After adding int1 to the array: int1 (retaincount): 2 int2 (retaincount): 0

After assigning values: int1 (retaincount): 2 int2 (retaincount): 2

After int1 retain: int1 (retaincount): 3 int2 (retaincount): 3

After int1 release: int1 (retaincount): 2 int2 (retaincount): 2

After int1 is deleted from the array: int1 (retaincount): 1 int2 (retaincount): 1

Some methods provided by the Basic Framework also increase the number of object references, for example, when an object is added to an array.

In the preceding example, the int1 value of the nsnumber object is set to an integer of 222. int2 is defined but not initialized. At this time, the reference counter is printed, and the int1 counter is 1, and the int2 counter is 0. That is, the reference counter is added only after an object is created and initialized normally.

Then, use addobject: to add int1 to the array arr1 and print the counter. It is not difficult to find that the counter of int1 is changed to 2, and the counter of int2 is still 0. That is to say, when an object is added to any type of set, the effective reference of the modified object will be added.

Next, assign the int1 value to int2. The result at this time is worth noting. The reference counters of int1 and int2 are both 2, which means that the value assignment operation does not increase the counter of int1, but the counter of int2 is changed to 2. This is because when int1 is assigned to int2, the actual object is not copied, but the memory of the object is passed to int2. That is to say, the two pointers point to the same object.

Then we send a retain message to int1 to increase the reference count, and the reference counter of int2 also increases.

Then, send the release message to int1. the reference count of int1 and int2 is certainly reduced by 1 at the same time.

Finally, remove int1 from arr1, so that the reference count of int1 and int2 is reduced by 1 at the same time. However, at this time, the object is not actually released because the counter 1 is not 0. If you want to release it, You have to release it once.

Objective-C memory management system is based on reference count. We need to track the reference and whether the memory is actually released during the runtime. To put it simply, you need to call release every time you call alloc or retain.

In the program, you track only one object in two cases: (1) local variables (used temporarily in a method, such as creating a string) (2) to become a member variable of a class, you only need to master the situation of the tracker and release the corresponding memory, and you have basically mastered the memory management of objective-C.

Iii. string processing

If you use alloc or copy to create an object (such as a string), you need to release or autorelease the object at the end of the method. If we create it in another way, we can ignore it. In the following particles, you only need to release the objects created using alloc:

Nsnumber * num1 = [[nsnumber alloc] initwithfloat: 1.80]; nsnumber * num2 = [nsnumber numberwithfloat: 145.0]; // we only need to release num1, do not release num2 [num1 release];

Let's look at the following example:

Int main (INT argc, char * argv []) {ngutoreleasepool * Pool = [[ngutoreleasepool alloc] init]; nsstring * str1 = @ "Liuwei "; nsstring * str2 = [nsstring stringwithstring: @ "iukey"]; nsmutablestring * str3 = [nsmutablestring stringwithstring: @ "masterliuwei"]; nsmutablearray * arr1 = [javasarray]; // After initialization, each retaincount: str1: fffffffffff str2: character str3: 1 [arr1 addobject: str1]; [arr1 addobject: str2]; [arr1 addobject: str3]; // after adding the string to the array, each retaincount: str1: fffffffffffffff str2: fffffffffffff str3: 2 [str1 retain]; [str2 retain]; [str3 retain]; // After retain is executed, each retaincount: str1: fffffffffffff str2: Getting str3: 3 [str3 release]; // after release is executed, each retaincount: str1: fffffffffffffff str2: Getting str3: 2 [pool drain]; return 0 ;}

You may have questions about the results. Why is it fffffffffffff? In the program, str1, The nsstring object, is assigned a static string @ "welcome ". The memory allocation method of string constants is different from that of other objects. This method does not reference the counting mechanism, so these objects cannot be released forever. When a retaincount message is sent to str1, it returns fffffffffffff, which is the largest unsigned integer. Note: this applies to initializing immutable string objects with string constants.

Note the following statements:

NSMutableString* str3 = [NSMutableString stringWithString:@"MasterLiuWei"];

This statement uses a String constant to initialize a variable String object. It is executed using the stringwithstring: method. The variable string may change during the program running. However, the string constant cannot be changed, so the system copies the String constant to str3. Therefore, variable string objects have reference counts.

When we use the stringwithstring: method to create an immutable String object, this object is actually added to the Auto Release pool. The arr1 object created using the array method is also added to the Auto Release pool.

The code block in the program adds these strings to the array, and the refrigerator sends a retain message to the recipient. From the results of the program, we can see that these operations have changed their reference technology.

Str3 has been released once before the automatic release pool is released. Therefore, the reference count of str3 is changed to 2. Then, the release of the automatic release pool reduces the number of referenced technologies to 0, which causes them to be released. When the automatic release pool is released, each object in the pool will receive a release message (the number of received messages equals to the number of autorelease messages sent at that time ). Because when str3 is created using the stringwithstring: method, the system adds it to the Auto Release pool, that is, autorelease is called.
So when the automatic release pool is released (drain), str3 receives a release message, which will reduce its reference count to 1. When the array in the Auto Release pool is released, each element in the array is also released. Therefore, each element in the array receives a release message, this changes the reference count of str3 to 0. The system will call the dealloc method of str3 to release str3.

NOTE: If we release the program excessively, it will terminate abnormally.

Iv. class member variables

In most cases, the setter method of a member variable should only be the old object of aytorelease/release, and then retain/copy the new object. We only need to call release in dealloc. So what really needs to be managed is the reference of local variables inside the method. For example, set a string (using copy ):

-(Void) setname :( nsstring *) newname {If (name! = Newname) {[Name Release]; name = [newname copy]; // the counter of name is 1 }}

The following is another example of using retain to manage Member objects:

- (void) setScore:(NSNumber*)inputScore{    [score autorelease];    score = [inputScore retain];}
- (void)dealloc{    [score release];    [super dealloc];}

The following is an example of using a local object to set a member variable:

  NSNumber* value1 = [[NSNumber alloc]initWithFloat:180.0];    [self setScore:value1];        NSNumber* value2 = [NSNumber numberWithFloat:72.5];    [self setScore:value2];    [value1 release];

Next I will analyze the handling methods of several member variables.

First, define a class that only contains the name attribute of the nsstring type, and manually write the access method for this attribute.

#import <Foundation/Foundation.h>@interface Student : NSObject{    NSString* name;}-(void)setName:(NSString*)s;-(NSString*)name;@end

In the method implementation file below, we directly assign the value of the parameter S in setname: Method to the name attribute without any other operations.

#import "Student.h"@implementation Student-(void)setName:(NSString *)s{    name =s;}-(NSString*)name{    return name;}@end

The following is the test code:

Nsmutablestring * str1 = [nsmutablestring stringwithstring: @ "Liuwei"]; Student * Stu = [[STUDENT alloc] init]; nslog (@ "Reference Counter of str1: % x ", [str1 retaincount]); [STU setname: str1]; nslog (@ "Reference Counter of str1: % x", [str1 retaincount]); [STU release];

Test results:

Reference Counter of str1: 1

Reference Counter of str1: 1

The program first creates an object Stu for the student class and then calls the setname method of this object, set the value of name to the value of str1 (the str1 and name pointers point to the same memory space ). This method has a problem. After setting, if the str1 object is not required and released, the Reference Counter of str1 is changed to 0. Undoubtedly, the Reference Counter of name will also change to 0, and the value stored in it will become invalid.

Because str1 is created using the nsmutablestring stringwithstring: method, this object is automatically added to the Auto Release pool (although the object is not explicitly added to the Auto Release pool ). Therefore, when the pool is automatically released, str1 will also be released. In this case, access to any object pointed to by str1 will be invalid.

Let's look at the second method. The interface file has not been changed, so refer to the interface code above. The [name retain] method is executed in the implementation file, which increases the reference counter of name by 1, so that the name can be used normally when str1 is released.

#import "Student.h"@implementation Student-(void)setName:(NSString *)s{    name =s;    [name retain];}-(NSString*)name{    return name;}@end

Test again:

Nsmutablestring * str1 = [nsmutablestring stringwithstring: @ "Liuwei"]; Student * Stu = [[STUDENT alloc] init]; nslog (@ "Reference Counter of str1: % x ", [str1 retaincount]); [STU setname: str1]; nslog (@ "Reference Counter of str1: % x", [str1 retaincount]); [STU release]; nslog (@ "Reference Counter of str1: % x", [str1 retaincount]);

Test results:

Reference Counter of str1: 1

Reference Counter of str1: 2

Reference Counter of str1: 1

According to the result, after setname: is called, the Reference Counter of str1 is changed to 2, and the problem generated in the previous program is solved. Then, the [str1 release] method is executed in the program to reduce the reference counter of str1 to 1. At this time, the reference to name is still valid.

Because the program uses the alloc method to create the student class object, it is responsible for releasing this object. You can manually release it, or call its autorelease method to add it to the Auto Release pool. Before that, we can use this object normally.

However, there are still some problems with this method. The setname: method retains the string object passed in as a parameter. But when will this object be released? When the name value is changed multiple times, what will happen to the original values? Should the memory they occupy be released?

The final solution is as follows:

//  Student.h#import <Foundation/Foundation.h>@interface Student : NSObject{    NSString* name;}-(void)setName:(NSString*)s;-(NSString*)name;- (void)dealloc;@end
//  Student.m#import "Student.h"@implementation Student-(void)setName:(NSString *)s{    [name autorelease];    name = [s retain];}-(NSString*)name{    return name;}- (void)dealloc{    [name release];    [super dealloc];}@end

Test code:

Nsmutablestring * str1 = [nsmutablestring stringwithstring: @ "Liuwei"]; Student * Stu = [[STUDENT alloc] init]; nslog (@ "Reference Counter of str1: % x ", [str1 retaincount]); [STU setname: str1]; nslog (@ "Reference Counter of str1: % x", [str1 retaincount]);

Test results:

Reference Counter of str1: 1

Reference Counter of str1: 2

In the above method, No matter what value is currently stored in name, we first manually add it to the Auto Release pool in setname: method, this also allows the name to be automatically released in the future. When the setname: method is called multiple times in the program, this operation will be more important: each time a new value is stored, the value of the variable must be marked as automatically released, keep the new value in name.

When the system releases an object, the system automatically calls the dealloc method. Objects that are retained, objects that are allocated using alloc, or objects that are copied in a method can be released in the dealloc method. First, release the name variable, because it is a persistence object: Then call the dealloc method of the parent class to release the student object. If you want external strings to be completely independent from the parameters of the Setting method, you can claim a new copy of the string in the setting method, that is, use the copy option.

5. autorelease pool

A string is created in the Code. If you need to return this string, you need to use autorelease instead of release. For example:

-(Nsstring *) getstr {nsstring * STR; STR = [[nsstring alloc] initwithformat: @ "result return"]; // [STR release]; // cannot be released, otherwise, the caller cannot obtain the returned value [STR autorelease]; // return STR correctly ;}

By using autorelease, the object is put into the Auto Release pool. The system automatically tracks the usage of each object and

Release all objects in the pool when the pool is automatically released

Note: autorelease is not a garbage collection function. Objective-C on the iPhone operating system does not have the garbage collection function. In addition, you can create multiple Auto Release pools.

int main(int argc, char *argv[]){    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc]init];    Student* stu =[[Student alloc]init];//1    NSLog(@"%x",[stu retainCount]);        [pool drain];    NSLog(@"%x",[stu retainCount]);//1        pool =[[NSAutoreleasePool alloc]init];    [stu autorelease];    NSLog(@"%x",[stu retainCount]);//1        [stu retain];    NSLog(@"%x",[stu retainCount]);//2        [pool drain];    NSLog(@"%x",[stu retainCount]);//1    [stu release];        return 0;}

6. Memory leakage

To prevent memory leaks and ensure the most effective use of memory, the application should load data only when needed ., For example, the user clicks a button to display the relevant data. We mentioned autorelease earlier. But if your code is always autorelease, will there be no memory leakage? The problem is when the autorelease pool is released. Every time an application is executed, the system automatically creates an autorelease pool. The system does not immediately release the objects in the autorelease pool, but is released after a run loop, generally at a subtle level. In
Objects in the autorelease pool can be released immediately, but it is very likely that the system will release them after a while. Therefore, using release can release the memory more effectively. Therefore, we should try to manage the memory by ourselves and do not rely too much on autorelease. In addition, some System Objects use autorelease, such as nsstring. You can use Ziji to manage memory classes, such as nsmutablestring. you can create your own pool.

Below are several basic principles for memory management:

1> if you use the alloc (or copy) method to create an object, or use retain to keep an object, you must release the object yourself.

2> in most cases, the number of statements applying for memory should be equal to the number of statements releasing memory.

3> use as little memory as possible and release immediately after use

VII. Copy and nonatomic

For attribute variables of the string type, we often use statements similar to the following:

@property(nonatomic,copy)NSString* name;

This statement is equivalent:

-(void)setName:(NSString *)s{    if (s != name) {        [name release];        name = [s copy];    }}

So why should we use copy? If the following statement is used directly, what will happen?

-(void)setName:(NSString *)s{    name = s;}

The result is that both name and s point to the same object. After the setname: method is called, if the value of S is modified, this is obviously not the expected result. Therefore, to use copy to copy the value of S to name, the function is to call an alloc method to create a New String object (initwithstringls ).

In multithreading, two or more threads may execute the same code at the same time. To prevent this, developers can use mutex locks. Nonatomic means that no mutex lock is required. Atomic uses a mutex lock. The default value is atomic. If your program does not have multiple threads, you can set it to nonatomic to save resources.

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.