Preface
When I was a beginner at objectice-C, I always felt confused about the memory management mechanism of objective-C. The program often experienced memory leaks or inexplicable crashes. I have summarized my research achievements and experience on the objective-C memory management mechanism, and wrote such a simple tutorial. I hope it will be helpful to you and you are welcome to discuss it together. The memory management involved in this article is for Classes inherited from nsobject. From http://vinceyuan.cnblogs.com/
Basic Principles
Objective-C's memory management mechanism is different from the fully automatic garbage collection mechanism of. Net/Java. It is essentially a manual management method in C language, but it only adds some automatic methods.
1. The objective-C object is generated on the heap. After being generated, a pointer is required to point to it.
Classa * obj1 = [[classa alloc] init];
2. The objective-C object will not be automatically destroyed after use. You need to execute dealloc to release space (destroy); otherwise, the memory will be leaked.
[Obj1 dealloc];
This brings about a problem. In the following code, does obj2 need to call dealloc?
Classa * obj1 = [[classa alloc] init];
Classa * obj2 = obj1;
[Obj1 Hello]; // output hello
[Obj1 dealloc];
[Obj2 Hello]; // can this row and the next row be executed?
[Obj2 dealloc];
No, because obj1 and obj2 only refer to the needle and point to the same object. [obj1 dealloc] has destroyed this object and cannot call [obj2 Hello] or [obj2 dealloc]. Obj2 is actually an invalid pointer.
How to Avoid invalid pointers? See the next one.
3 objective-C uses the reference count (ref count or retain count ). The number of times the object is referenced. For example, if an object is pointed to (referenced) by two pointers, its retain count is 2. Dealloc is called rather than release when objects need to be destroyed. Release will reduce retain count by 1. Only when retain count is equal to 0 will the system call dealloc to actually destroy this object.
Classa * obj1 = [[classa alloc] init]; // when an object is generated, retain COUNT = 1
[Obj1 release]; // release: reduce retain count by 1, retain COUNT = 0, dealloc is automatically called, and the object is destroyed
Let's look back at the problem with the Invalid Pointer. Have you solved the problem by changing dealloc to release?
Classa * obj1 = [[classa alloc] init]; // retain COUNT = 1
Classa * obj2 = obj1; // retain COUNT = 1
[Obj1 Hello]; // output hello
[Obj1 release]; // retain COUNT = 0, the object is destroyed
[Obj2 Hello];
[Obj2 release];
After [obj1 release], obj2 is still an invalid pointer. The problem persists. For the solution, see the next one.
4 when the objective-C pointer is assigned a value, retain count will not be automatically added and manual retain is required.
Classa * obj1 = [[classa alloc] init]; // retain COUNT = 1
Classa * obj2 = obj1; // retain COUNT = 1
[Obj2 retain]; // retain COUNT = 2
[Obj1 Hello]; // output hello
[Obj1 release]; // retain COUNT = 2-1 = 1
[Obj2 Hello]; // output hello
[Obj2 release]; // retain COUNT = 0, object destroyed
Solve the problem! NOTE: If [obj2 release] is not called, The retain count of this object is always 1 and will not be destroyed, causing memory leakage. (1-4 can refer to the example program memman-no-pool.m in the attachment)
It does not leak memory, but it seems a little troublesome. Is there a simple way? See the next one.
5. The autorelease pool (automatically released Object pool) is introduced in objective-C. objects can be automatically released when some rules are followed. (Autorelease pool is still not the fully automated garbage collection mechanism of. Net/Java)
5.1 for newly generated objects, you only need to call autorelease. You do not need to call release any more!
Classa * obj1 = [[classa alloc] init] autorelease]; // retain COUNT = 1 but no need to call release
5.2
For pointer assignment, the code is similar to the previous one.
Classa * obj1 = [[classa alloc] init] autorelease]; // retain COUNT = 1
Classa * obj2 = obj1; // retain COUNT = 1
[Obj2 retain]; // retain COUNT = 2
[Obj1 Hello]; // output hello
// For obj1, you do not need to call (actually cannot call) Release
[Obj2 Hello]; // output hello
[Obj2 release]; // retain COUNT = 2-1 = 1
Careful readers will surely find that this object has not been destroyed. When will it be destroyed? Who will destroy it? (Refer to the example program memman-with-pool.m in the attachment) see the next one.
6 autorelease pool principle analysis. (In fact, it is very simple. You must stick to it. Otherwise, you still cannot understand the objective-C memory management mechanism .)
6.1 autorelease pool is not born and needs to be created manually. Only when you create an iPhone project, xcode will automatically help you write it. The real name of autoreleasepool is NSAID utoreleasepool.
NSAID utoreleasepool * Pool = [[NSAID utoreleasepool alloc] init];
6.2 The nsmutablearray array is contained in the nsmutoreleasepool to save all objects declared as autorelease. If an object is declared as autorelease, the system will add this object to this array.
Classa * obj1 = [[classa alloc] init] autorelease]; // retain COUNT = 1, add this object to autorelease pool
6.3 when the NSAID utoreleasepool itself is destroyed, it traverses this array and each member in the release array. If the retain count of the members in the array is 1 at this time, after release, the retain count is 0, and the object is officially destroyed. If the retain count of the members in the array is greater than 1 at this time, the retain count is greater than 0 after release, and the object is still not destroyed, causing memory leakage.
6.4 by default, there is only one autorelease pool, which is usually similar to the following example.
Int main (INT argc, const char * argv [])
{
NSAID utoreleasepool * pool;
Pool = [[NSAID utoreleasepool alloc] init];
// Do something
[Pool release];
Return (0 );
} // Main
All objects marked as autorelease are destroyed only when the program exits (when the pool is destroyed. If you have a large number of objects marked as autorelease, this obviously cannot make good use of the memory, it is very easy to cause insufficient memory in iPhone memory-constrained programs. For example:
Int main (INT argc, const char * argv [])
{
NSAID utoreleasepool * Pool = [[NSAID utoreleasepool alloc] init];
Int I, J;
For (I = 0; I <100; I ++)
{
For (j = 0; j <100000; j ++)
[Nsstring stringwithformat: @ "1234567890"]; // The generated object is autorelease.
}
[Pool release];
Return (0 );
} // Main
(You can refer to the example program memman-many-objs-one-pool.m in the attachment, through the monitoring tool at run time you can find that there is a sharp increase in the use of the internal, until the pool is released upon destruction) You need to consider the next one.
7. Multiple autorelease pools can be nested in the objective-C program. When you need to create a large number of local variables, you can create an embedded autorelease pool to release the memory in time.
Int main (INT argc, const char * argv [])
{
NSAID utoreleasepool * Pool = [[NSAID utoreleasepool alloc] init];
Int I, J;
For (I = 0; I <100; I ++)
{
NSAID utoreleasepool * looppool = [[NSAID utoreleasepool alloc] init];
For (j = 0; j <100000; j ++)
[Nsstring stringwithformat: @ "1234567890"]; // The generated object is autorelease.
[Looppool release];
}
[Pool release];
Return (0 );
} // Main
(You can refer to the example program memman-many-objs-many-pools.m in the attachment for minimal memory usage changes)
Tips and Paradigm
1 tip.
1.1 who created and who released (similar to "Who polluted and who managed "). If you pass
To create an object, you must call release or autorelease. In other words, if it is not created by you, you do not need to release it.
For example, if alloc generates an object in a function and the object is only used in this function, you must call release or autorelease in this function. If you alloc a member object in a class method and do not call autorelease, you need to call release in the dealloc method of this class; If autorelease is called, you do not need to do anything in the dealloc method.
1.2 all objects created by methods except alloc, new, or copy are declared as autorelease.
1.3 who retain and who release. If you call retain, you must call release no matter how the object is generated. Sometimes there is no retain in your code, but the system will add it to the default implementation. I do not know why Apple's documentation does not emphasize this very important point. Please refer to Chapter 2.7 and Chapter 3 of the paradigm.
2 paradigm.
The paradigm is the template. Because different people have different understandings and habits, the paradigm I have summarized may not be suitable for everyone, but I can ensure that there will be no problems in doing so.
2.1 create an object.
Classa * obj1 = [[classa alloc] init];
2.2 create an autorelease object.
Classa * obj1 = [[classa alloc] init] autorelease];
2.3 release an object and immediately clear the pointer. (By The Way, release is valid for a blank needle, but nothing will happen)
[Obj1 release];
Obj1 = nil;
2.4 assign a pointer to another pointer.
Classa * obj2 = obj1;
[Obj2 retain];
// Do something
[Obj2 release];
Obj2 = nil;
2.5 create and return an object in a function. You need to set this object to autorelease
Classa * func1 ()
{
Classa * OBJ = [[classa alloc] init] autorelease];
Return OBJ;
}
2.6 call the dealloc method of the base class in the dealloc method of the subclass
-(Void) dealloc
{
...
[Super dealloc];
}
2.7 create and use property in a class.
2.7.1 declare a member variable.
Classb * objb;
2.7.2 declare property and add the retain parameter.
@ Property (retain) classb * objb;
2.7.3 define property. (For the default implementation of property, see Chapter 3)
@ Synthesize objb;
2.7.4 apart from the dealloc method, property is always called using the. Operator.
Self. objb or obja. objb
2.7.5 release Member changes in the dealloc method.
[Objb release];
The sample code is as follows (For details, refer to the memman-property.m in the attachment, and you need to pay special attention to when the object is destroyed .) :
@ Interface classa: nsobject
{
Classb * objb;
}
@ Property (retain) classb * objb;
@ End
@ Implementation classa
@ Synthesize objb;
-(Void) dealloc
{
[Objb release];
[Super dealloc];
}
@ End
2.7.6 when assigning values to this property, there are two methods: manual release and autorelease.
Void funcnoautorelease ()
{
Classb * objb1 = [[classb alloc] init];
Classa * obja = [[classa alloc] init];
Obja. objb = objb1;
[Objb1 release];
[Obja release];
}
Void funcautorelease ()
{
Classb * objb1 = [[classb alloc] init] autorelease];
Classa * obja = [[classa alloc] init] autorelease];
Obja. objb = objb1;
}
3. Default Implementation of @ property (retain) and @ synthesize
Here we will explain what happened to @ property (retain) classb * objb; and @ synthesize objb; (default Implementation of retain property ). Property is actually getter and setter, for the property with the retain parameter, the implementation behind it is as follows (see the memman-getter-setter.m in the attachment, you will find that the result is the same as the memman-property.m ):
@ Interface classa: nsobject
{
Classb * objb;
}
-(Classb *) getobjb;
-(Void) setobjb :( classb *) value;
@ End
@ Implementation classa
-(Classb *) getobjb
{
Return objb;
}
-(Void) setobjb :( classb *) Value
{
If (objb! = Value)
{
[Objb release];
Objb = [value retain];
}
}
In setobjb, if the new value is different from the original value, you must release the original value object once to ensure that retain count is correct.
Because we retain the class once (though implemented by default), we need to release the member variation in the dealloc method.
-(Void) dealloc
{
[Objb release];
[Super dealloc];
}
Additional instructions
When studying retain count, I do not recommend using nsstring. Because in the following statement,
Nsstring * str1 = @ "constant string ";
The retain count of str1 is a large number.
Objective-C performs special processing on constant strings.
Of course, if you create an nsstring like this, the retain count is still 1.
Nsstring * str2 = [nsstring stringwithformat: @ "123"];
From: http://www.cocoachina.com/macdev/objc/2010/0308/550_6.html