If the life cycle of an object is obvious, it is easy to know when the new object is to be used and when it is no longer needed, in which case the manual retain and release are used directly to determine its survival and death. But sometimes it's not that easy to know when an object is no longer in use. If the following code, it looks very simple:
Sample.h Class Interface Section
#import < Foundation / Foundation.h > @interface Sample : NSObject { } -( NSString *) toString; @end |
SAMPLE.M Class Implementation Section
#import "Sample.h" @implementation sample -( nsstring *) toString { &NBSP;&NBSP;&NBSP;&NBSP; nsstring * str = [[ nsstring alloc] initwithformat:@ "This is%@ class" ,@ "Sample" ]; &NBSP;&NBSP;&NBSP;&NBSP; return STR; } @end |
Called in the main function
#import <Foundation/Foundation.h>
#import "Sample.h"
int
main (
int
argc,
const
char
* argv[]) {
Sample *s = [Sample
new
];
NSLog
(@
"%@"
,[s toString]);
[s release];
return
0;
}
|
I do not know if you realize that this code has a memory leak problem, because SAMPLE.M's ToString method generates an instance of the NSString class, but the main function finally releases only the instance S of sample, but does not release the string instance of the NSString Class!
To correct this error, the main function should be changed to:
int
main (
int
argc,
const
char
* argv[]) {
Sample *s = [Sample
new
];
NSString
* str = [s toString];
NSLog
(@
"%@"
,str);
[str release];
//手动释放NSString字符串实例
[s release];
return 0;
}
|
This hidden error can easily occur and is easily overlooked. For this obj-c reference to the Autorelease pool, each time you create a project with Xcode, you may have noticed a code template similar to the following:
int
main (
int
argc,
const
char
* argv[]) {
NSAutoreleasePool
* pool = [[
NSAutoreleasePool
alloc] init];
//insert code here...
NSLog
(@
"Hello,World!"
);
[pool drain];
return
0;
}
|
That is, Xcode writes a layer of NSAutoreleasePool to the developer's code. This pool is similar to a stack in a data structure (stack), which is equivalent to a container, and each time an object calls the Autorelease method (the formal argument in obj-c should be that the object sends a autorelease message), the object's reference count does not really change. Instead, add a record to the pool and note the object's requirements. Finally, when the pool sends a drain or release message, this requirement for all objects in the pools is executed (that is, all objects in the pool are notified before the pooling is destroyed, and all the release messages are actually reduced by the reference count. If the object has previously sent a autorelease message)
Let's take a look at the basic use, first add a property int flag to sample (to see which instance is being destroyed when destroying), and rewrite dealloc () to output some information when released
Sample.h
#import <Foundation/Foundation.h> @interface Sample : NSObject { } -( NSString *) toString; //增加一个int型的属性flag @property int flag; @end |
Sample.m
#import "Sample.h"
@implementation Sample
//自动生成属性flag的setter与getter方法
@synthesize
flag;
-(
NSString
*) toString
{
NSString
* str = [[
NSString
alloc] initWithFormat:@
"This is Sample%d"
,flag];
return
str;
}
-(
void
)dealloc
{
NSLog
(@
"Sample %d is going to die."
,flag);
[
super dealloc];
}
@end
|
Use the main function after automatically releasing the pool
#import <Foundation/Foundation.h>
#import "Sample.h"
int
main (
int
argc,
const
char
* argv[]) {
NSAutoreleasePool
* pool = [[
NSAutoreleasePool
alloc] init];
Sample *s1 = [Sample
new
];
Sample *s2 = [Sample
new
];
s1.flag=1;
s2.flag=2;
[s1 autorelease];
[s2 autorelease];
[pool drain];
return 0;
}
|
The result of the operation is:
2011-02-24 13:28:09.759 memorymanage[282:a0f] Sample 2 is going to die.
2011-02-24 13:28:09.769 memorymanage[282:a0f] Sample 1 is going to die.
From the results, the pool is a last-in-first-out, i.e. the first release of the final autorelease (conforming to the characteristics of the stack data structure). Then go back to the problem of memory leaks in the ToString method mentioned earlier, after understanding the basic principle of pool, just replace the return str with retrun [str autorelease], that is, the string is registered in the pool, so when [pool drain], All enlisted objects are automatically called the release method and are freed.
The auto-release pool is functionally understood as a delay-release technique: by sending a autorelease message, registering with the auto-release pool, indicating that it will send release messages to destroy itself when the pool is destroyed.
Finally, some points to note:
1, nsautoreleasepool instance pool itself is also an object, also need to release, so the end also need [pool release] or [pool drain], it is this line of code, it will be all the objects in the pool are released simultaneously. ---Note: Drain is only available for Max OS High version, low version not applicable, and release generic, the other is not much different
2, pool in release, just simply let all the objects in the pool send release, there is no other mystery. (that is, the reference count for all objects in the pool is reduced by 1) so if you have previously forced retain of a reference count for an object, even if the pool is release, the objects in the pools are still likely to be destroyed because the reference count is still greater than 1. For example, the following code:
+ View Code
Operation Result:
2011-02-24 13:49:22.558 memorymanage[461:a0f] S1.retaincount=1,s2.retaincount=1
2011-02-24 13:49:22.566 memorymanage[461:a0f] S1.retaincount=1,s2.retaincount=1
2011-02-24 13:49:22.567 memorymanage[461:a0f] s1.retaincount=1,s2.retaincount=2
2011-02-24 13:49:22.578 memorymanage[461:a0f] Sample 1 is going to die.
Because S2 sends a retain message, it increases its reference count to 2, so eventually S2 is not destroyed even after the pool is released.
3, in Iphone/ipad and other memory limited handheld devices, do not recommend the use of autorelease, because in the final analysis this is a delay release, if your program has been running, the code has not been implemented to [pool release], even if there are many objects no longer needed, But the memory they occupy is not really released.
4, do not put a lot of cyclic operation between the same nsautoreleasepool, the same reason, so that the pool has a large number of objects, causing the program to occupy more memory at run time. For example, the following code:
int
main (
int
argc,
const
char
* argv[]) {
NSAutoreleasePool
* pool = [[
NSAutoreleasePool
alloc] init];
int
i;
for
(i=0;i<10000;i++){
Sample *s = [Sample
new
];
s.flag = i;
NSLog
(@
"%@"
,[s toString]);
[s autorelease];
}
[pool release];
return
0;
}
|
When the above code runs, it must wait until the end of the loop before destroying the object. This can be improved for the following:
int
main (
int
argc,
const
char
* argv[]) {
NSAutoreleasePool
* pool = [[
NSAutoreleasePool
alloc] init];
int
i;
for
(i=0;i<10000;i++){
Sample *s = [Sample
new
];
s.flag = i;
NSLog
(@
"%@"
,[s toString]);
[s autorelease];
if
(i % 100==0)
{
[pool release];
pool = [[
NSAutoreleasePool
alloc] init];
}
}
[pool release];
return 0;
}
|
So that whenever there are 100 objects in the pool, it is released once, so that the program consumes much less memory when it runs.
Finally from the book to copy a section called Cocoa Memory management Golden Law: If I use the new, Alloc or copy method to get an object, then I must release (release) or automatically release (Autorelease) the object
Original:
OBJECTIVE-C Memory Management-Automatic release pool (autorelease)
OBJECTIVE-C Memory Management-Automatic release pool (autorelease)