How to avoid Memory leakage in iPhone applications

Source: Internet
Author: User

When creating an object, the ownership is created through alloc, new, or copy, and then the ownership of the object is assigned and copied by calling the retain or using the Cocoa function. There are two ways to release the memory: one is to explicitly request to release the ownership of the object, and the other is to use the auto-release pool ).

There is a reference-related computing system behind the ownership. Most iPhone SDK objects use this system and establish strong references between them.

When you create an object, the reference value is 1. If you call retain once, the reference value of the object is increased by 1. If you call release once, the reference value of the object is reduced by 1, when the reference value is 0, the Ownership Allocation of the object will be canceled. Using the Auto Release pool means that the ownership of the object will be automatically canceled after a delay.

Weak references can also be created between objects, which means that the reference value is not retained and the allocation of objects needs to be canceled manually.

When to use retain?

When do you want to prevent objects from being released before use?

Each time you use the copy, alloc, retain, or Cocoa function to create and copy ownership, you need the corresponding release or auto-release.

Developers should consider objects from the perspective of ownership without worrying about reference values. As long as you have the corresponding retain and release methods, you can perform the + 1 and-1 operations on the reference values.

Note: you may want to use [object retainCount], but it may cause a return value error due to the underlying code of the SDK. This method is not recommended for memory management.

Automatic release

Setting the object to Auto Release means you do not need to explicitly request release because they will be automatically released when the Auto Release pool is cleared. The iPhone runs the automatic release pool on the main thread to release objects after the event loop ends. When creating your own thread, you need to create your own automatic release pool.

There is a convenient constructor on the iPhone. objects created using this method are set to automatically released.

Example:

NSString * str0 = @ "hello ";

NSString * str1 = [NSString stringWithString: @ "world"];

NSString * str2 = str1;

You can use the following method to set an allocated object to Auto Release:

NSString * str = [[NSString alloc] initWithString: @ "the flash? "];

[Str autorelease];

Or use the following method:

NSString * str = [[NSString alloc] initWithString: @ "batman! "] Autorelease];

When the pointer is exceeded, or when the pool is automatically released, the ownership of the automatically released object will be canceled.

When an event loop ends, components in the automatically released pool are usually cleared. However, when your loop allocates a large amount of memory for each iteration, You may wish this would not happen. In this case, you can create an automatic release pool in the cycle. The automatic release pool can be nested, so when the internal pool is cleared, the allocated objects will be released. In the following example, objects are released after each iteration.

For (int I = 0; I <10; ++ I)

{

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

NSString * str = [NSString stringWithString: @ "hello world"];

[Self ProcessMessage: str];

[Pool drain];

}

Note: The iPhone does not support garbage collection During writing, so the drain and release functions the same. Drain is usually used when you want to set the OSX port for the program, unless a garbage collection mechanism is added to the iPhone later. Drain can be used to release memory.

Returns the pointer to an object.

When following the ownership rules, developers need to know which functions have the ownership of objects. The following is an example of returning a pointer to an object and releasing it.

Incorrect method:

-(NSMutableString *) GetOutput

{

NSMutableString * output = [[NSMutableString alloc] initWithString: @ "output"];

Return output;

}

-(Void) Test

{

NSMutableString * obj = [self GetOutput];

NSLog (@ "count: % d", [obj retainCount]);

[Obj release];

}

In this example, the output owner is GetOutput. Releasing obj from Test violates the rules in the Coccoa memory management guide. Although it will not leak the memory, this is not good, because Test should not release objects not owned by it.

The correct method:

-(NSMutableString *) GetOutput

{

NSMutableString * output = [[NSMutableString alloc] initWithString: @ "output"];

Return [output autorelease];

}

-(Void) Test

{

NSMutableString * obj = [self GetOutput];

NSLog (@ "count: % d", [obj retainCount]);

}

In the second example, the output is set to automatically release when GetOutput returns. When the reference value of output is reduced, GetObject releases the ownership of output. The Test function can now freely retain and release objects. Please ensure that it does not leak memory.

In this example, obj is set to automatically release, so the Test function does not have ownership of it, but what if it needs to store objects elsewhere?

In this case, the object must have a new owner to keep it.

Setters

The setter function must retain the object it stores, that is, the declared ownership. If we want to create a setter function, we need to do two things before assigning a new pointer to the member variable.

In the function:

-(Void) setName :( NSString *) newName

First, we need to reduce the reference value of the member variable:

[Name release];

This will allow the name object to be released when the reference value is 0, but it also allows other owners of the object to continue using the object.

Then we add the reference value of the new NSString object:

[NewName retain];

Therefore, when setName ends, newName will not be unallocated. NewName currently points to different objects than name points to. The two have different reference values.

Now we set the name to point to the newName object:

Name = newName;

But what if name and newName are the same object? We cannot keep it after it is released and release it again.

Retain the new object before releasing the stored object:

[NewName retain];

[Name release];

Name = newName;

Now the two objects are the same. First, add the reference value and then reduce it, so that the reference value remains unchanged before the value is assigned.

Another approach is to use objective-c:

The statement is as follows:

@ Property (nonatomic, retain) NSString * name;

1. nonatomic indicates that multiple threads that obtain data at the same time are not grouped. Atomic locks data for a single thread, but it is not necessary because it is slow.

2. retain indicates that we want to keep the newName object.

We can use copy instead of retain:

@ Property (nonatomic, copy) NSString * name;

This is the same as the following function:

-(Void) setName :( NSString *) newName

{

NSString * copiedName = [newName copy];

[Name release];

Name = copiedName;

[Name retain];

[CopiedName release];

}

NewName is copied to the copiedName here, and now the copiedName has a copy of the string. The name is released, and the copiedName is assigned to the name. Then the name retains the string so that both the copiedName and name have it. Finally, copiedName releases this object, and name becomes the unique owner of this string.

If we have the following functions, setters like this will be input to keep member objects:

-(Void) Test

{

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

// Do something...

Name = [self GetOutput];

// Do something else...

NSLog (@ "Client Name before drain: % @", name );

[Pool drain];

NSLog (@ "Client Name after drain: % @", name );

}

Name is undefined after it is called to drain, because when the pool is released, the name will also be released.

If we replace the value assignment with the following parts:

[Self setName: [self GetOutput];

The name will be owned by this class and will be retained for use until the release is called.

So when will we release the object?

Since name is a member variable, the safest way to release it is to use the dealloc function for its class.

-(Void) dealloc

{

[Name release];

[Super dealloc];

}

Note: Although dealloc is not always called, it may be dangerous to release objects by dealloc, which may trigger unexpected things. At the exit, the iPhone OS may clear the memory of all applications before calling dealloc.

When using setter to assign values to objects, be careful with the following statements:

[Self setName: [[NSString alloc] init];

The name settings are correct, but alloc is not released. The following method is better:

NSString * s = [[NSString alloc] init];

[Self setName: s];

[S release];

Or use auto release:

[Self setName: [[NSString alloc] init] autorelease];

Auto Release pool

The automatic release pool releases objects between the allocation and drain functions.

Set a loop in the following function, assign a copy of NSNumber to magicNumber in the loop, and set magicNumber to Auto Release. In this example, we want to clear the automatic release pool during each iteration (this can save the memory of the loop when the number of values is large)

-(Void) Test

{

NSString * clientName = nil;

NSNumber * magicNumber = nil;

For (int I = 0; I <10; ++ I)

{

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

MagicNumber = [[self GetMagicNumber] copy];

[MagicNumber autorelease];

If (I = [magicNumber intValue])

{

ClientName = [self GetOutput];

}

[Pool drain];

}

If (clientName! = Nil)

{

NSLog (@ "Client Name: % @", clientName );

}

}

The problem is that clientName is assigned and released in the local automatic release pool. Therefore, when the external pool is cleared, clientName has been released, no further use of clientName is defined.

In this example, the clientName is retained after the value is assigned, and the clientName is released after the end:

-(Void) Test

{

NSString * clientName = nil;

NSNumber * magicNumber = nil;

For (int I = 0; I <10; ++ I)

{

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

MagicNumber = [[self GetMagicNumber] copy];

[MagicNumber autorelease];

If (I = [magicNumber intValue])

{

ClientName = [self GetOutput];

[ClientName retain];

}

[Pool drain];

}

If (clientName! = Nil)

{

NSLog (@ "Client Name: % @", clientName );

[ClientName release];

}

}

We obtain the clientName ownership when calling the retain and release functions. By adding a retain and release call, we can ensure that the clientName will not be automatically released before the call is released.

Set

When an object is added to an input set, it is owned by the set. In this example, we assign a string, which now has the owner;

NSString * str = [[NSString alloc] initWithString: @ "Bruce Wayne"];

Then we add it to the array, and now it has two owners:

[Array addObject: str];

We can safely release this string so that it is only owned by the array:

[Str release];

When a set is released, all objects in the set are released.

NSMutableArray * array = [[NSMutableArray alloc] init];

NSString * str = [[NSString alloc] initWithString: @ "Bruce Wayne"];

[Array addObject: str];

[Array release];

In the above example, we allocate an array and a string, then add the string to the array and release the array. This means that the string has only one owner and will not be released before we call [str release.

Passing pointers using threads

In this function, we pass the input from the string to the function DoSomething, and then release the input

-(Void) Test

{

NSMutableString * input = [[NSMutableString alloc] initWithString: @ "batman! "];

[NSThread detachNewThreadSelector: @ selector (DoSomething :) toTarget: self withObject: input];

[Input release];

}

DetatchNewThreadSelector increases the reference value of the input object and releases it at the end of the thread. This is why we can release input at the beginning of the thread, regardless of when the function DoSomething starts or ends.

-(Void) DoSomething :( NSString *) str

{

[Self defined mselecw.mainthread: @ selector (FinishSomething :) withObject: str waitUntilDone: false];

}

The passed mseclecpolicmainthread also retains the passed object until the selector ends.

The automatic release pool is a special thread, so if we create an automatic release object on a new thread, we need to create an automatic release pool to release them.

[NSThread detachNewThreadSelector: @ selector (Process) toTarget: self withObject: nil];

The Process function is called in another thread.

-(Void) Process

{

NSAID utoreleasepool * pool = [[NSAID utoreleasepool alloc] init];

NSMutableString * output = [[NSMutableString alloc] initWithString: @ "batman! "] Autorelease];

NSLog (@ "output: % @", output );

[Self defined mselecw.mainthread: @ selector (FinishProcess) withObject: nil waitUntilDone: false];

[Pool drain];

}

The object output is assigned and set to automatically release in the Auto Release pool. It will be released before the function ends.

-(Void) FinishProcess

{

NSMutableString * output = [[NSMutableString alloc] initWithString: @ "superman? "] Autorelease];

NSLog (@ "output: % @", output );

}

The system automatically creates an automatic release pool for the main thread. Therefore, in FinishProcess, we do not need to create an automatic release pool for functions running on the main thread.

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.