OC language-memory management, oc-memory management
1. Introduction to memory management principles
Memory Management for 1.1C
Char * p = (char *) malloc (100 * sizeof (char ));
This is the dynamic memory allocation of C. We manually applied for 100 bytes of memory with the system; or the system opened up 100 bytes of space in the heap, return the first address of the space to the pointer Variable p.
Strcpy (p, "Hello World! ");
Copy the string to the memory space pointed to by the pointer Variable p.
Puts (p );
Print the string in the memory space pointed to by the p pointer.
Free (p );
After use, manually release the memory space with the system, or the system recycles the space. The above is the simple memory management in C.
C memory management. We apply for it manually and release it manually.
In this case, we only need to pay attention to two issues:
1. Apply for memory and release it after use. If it is not released, memory leakage will occur.
2. It cannot be released multiple times. If it is released multiple times, it will crash.
However, if the project is complex and requires the division of labor among dozens or hundreds of employees, the problem may easily occur.
For example, we have opened up a piece of memory space, which stores a piece of useful data. However, this data is not used only in this Code, but also in multiple places of the program. The result is that even if I use this memory, I cannot release it because I am not sure whether other people need to use it elsewhere. Memory leakage is inevitable.
2. OC Memory Management:Reference count
2.1 reference count
If one user (pointer) uses a dynamically applied memory, add 1 to the memory counter (which is in this object, this counter is reduced by 1. When the reference count of this memory is 0, we will release it. In this way, the above problem is solved. OC is used to manage the memory by reference count.
2.2 golden rule for Memory Management
For reference counting, there is a set of prime rules for memory management:
The basic rule to apply is everything that increases the reference counterwith alloc, [mutable] copy [withZone:] or retain is in charge of the corresponding [auto] release.
If you use alloc, [mutable] copy, and retain for an object, you must use the corresponding release or autorelease.
The common saying is who pollutes and who manages.
2.3MRC and ARC
ARC Automatic Reference Counting, Automatic Reference Counting. xcode helps us manage the memory.
MRC Manual Reference Counting: Manual Reference Counting. Memory is managed manually.
But for now, many companies still use MRC.
2.4 how to change the project to MRC
Xcode5: The project is ARC when it is created. If we want MRC, we need to make the following settings.
Select project-> target-> Bulid Settings-> Search: automatic reference counting or auto, and change Objective-C Automatic Reference Counting to NO.
3. Manual memory management operations (MRC)
3.1alloc and release
Create a new project. Do not change the memory management to manual
Create a Dog class
@interface Dog : NSObject @end @implementation Dog - (void)dealloc { NSLog(@"dog dealloc"); [super dealloc]; } @end
The destructor in dealloc will automatically call this method when the object is destroyed. We will rewrite this method here.
Write the following code in the main function:
Int main (int argc, const char * argv []) {@ autoreleasepool {Dog * dog = [[Dog alloc] init];} NSLog (@ "the program is about to exit "); return 0 ;}
According to the terminal printing information, the program has printed the dog dealloc before exiting the printing. That is to say, the dog object has been destroyed before the program runs. This is ARC. xcode helps us manage dog objects.
Change ARC to MRC and execute the program. The dog object is not destroyed.Because we manage them manually now, we need to follow the golden rule of memory management; Dog * dog = [[Dog alloc] init]; we need to perform release on dog.
Change the main function code to the following format:
Int main (int argc, const char * argv []) {@ autoreleasepool {Dog * dog = [[Dog alloc] init]; [dog release];} NSLog (@ "the program is about to exit"); return 0 ;}
Execute the program again. The print shows that the dog object has been destroyed. This is the golden rule. When we perform alloc on the dog, we need to perform release on the dog.
Note: release does not destroy objects, but reduces the reference count of objects by 1. When the reference count of objects is as fast as 0, the dealloc method is automatically called and the object is destroyed.
3.2 retain and retainCount
Retain to keep the object entry, that is, add 1 to the reference count of the object.
RetainCount: prints the reference count of an object.
Change the main function code to the following format:
Int main (int argc, const char * argv []) {@ autoreleasepool {Dog * dog = [[Dog alloc] init]; // The printed result at this time, the retainCount value is 1, // that is, alloc. When a dog object is created, the reference count of the object is 1 NSLog (@ "dog retainCount = % lu", [dog retainCount]); // The dog1 pointer must use (reference) the dog object. // in this case, to prevent the dog object from being release, // reduce the reference count by 1 to 0 and destroy the object, // We performed the retain operation. Dog * dog1 = [dog retain]; // The result is printed at this time. The retainCount value is 2 NSLog (@ "dog retainCount = % lu", [dog retainCount]); dog * dog2 = [dog retain]; // at this time, the printed results: dog, dog1, dog2, and retainCount are all 3, // because these three pointers point to the same object. NSLog (@ "dog retainCount = % lu", [dog retainCount]); NSLog (@ "dog1 retainCount = % lu", [dog1 retainCount]); NSLog (@ "dog2 retainCount = % lu", [dog2 retainCount]); // release does not destroy the object, so that the reference count of the object is reduced by 1 [dog release]; // The printed result at this time. The dog, dog1, dog2, and retainCount values are both 2. // although the dog executes the release, the dog pointer still points to the object. // At this time, dog only has the right to use the object, but does not have the right to possess it. NSLog (@ "dog retainCount = % lu", [dog retainCount]); NSLog (@ "dog1 retainCount = % lu", [dog1 retainCount]); NSLog (@ "dog2 retainCount = % lu", [dog2 retainCount]); [dog1 release]; [dog2 release]; // when the above two statements are executed, the dog object is destroyed. // Although we can write two [dog release] statements here; // the same effect can be achieved, but do not write it like this. // we must follow the golden rule of memory management: dog * dog = [[Dog alloc] init]; // This is the alloc of the dog pointer, which must correspond to [dog release]; Dog * dog1 = [dog retain]; // This Is A retain for the dog1 pointer, which corresponds to [dog1 retain]; // It is an incorrect usage to print the retainCount of dog at this time !! // Because the object has been destroyed !! Sending messages to a destroyed object is a logical error! // The program will crash. // The method of the dog object cannot be called because the dog object has been destroyed. // Note that it may not crash if no two rows are printed. NSLog (@ "dog retainCount = % lu", [dog retainCount]);} NSLog (@ "program is about to exit"); return 0 ;}
Used in 3.3 Class combination
In the above Code, add the Person class
@ Interface Person: NSObject {// a Person who raises a Dog * _ dog;}-(void) setDog :( Dog *) dog;-(Dog *) dog; @ end
SetDog method format:
@ Implementation Person/* the Person does not really hold the dog. If [dog release] is used in the main function, the reference count of dog is reduced by 1, and the dog is destroyed. -(Void) setDog :( Dog *) dog {_ dog = dog;} * // * if another Dog is held, the first dog will not be released and the memory will be leaked. -(Void) setDog :( Dog *) dog {_ dog = [dog retain];} * // * if a Dog is held, reset the dog and perform release first, at this time, it is very likely that the dog will be destroyed, and then there will be no way to retain again. -(Void) setDog :( Dog *) dog {[_ dog release]; _ dog = [dog retain];} * // standard syntax-(void) setDog :( Dog *) dog {if (_ dog! = Dog) {[_ dog release]; _ dog = [dog retain] ;}}- (Dog *) dog {return _ dog ;}- (void) dealloc {NSLog (@ "person dealloc"); // when a person destroys the dog object, the owner destroys [_ dog release]; [super dealloc];} @ end
Error Method Analysis:
// The first setDog: method error Dog * xiaoBai = [[Dog alloc] init]; Person * xiaoXin = [[Person alloc] init]; [xiaoXin setDog: xiaoBai]; // The reference count is 1 NSLog (@ "count = % lu", xiaoBai. retainCount); [xiaoBai release]; // The dog has been destroyed. Therefore, xiaoXin needs to hold the dog. [XiaoXin release]; // The second setDog: method error Dog * xiaoBai = [[Dog alloc] init]; Person * xiaoXin = [[Person alloc] init]; [xiaoXin setDog: xiaoBai]; // The reference count is 2 NSLog (@ "count = % lu", xiaoBai. retainCount); [xiaoBai release]; Dog * xiaoHei = [[Dog alloc] init]; [xiaoXin setDog: xiaoHei]; [xiaoHei release]; [xiaoXin release]; // at this time, the xiaoBai Dog is not released // The third setDog: the error Dog * xiaoBai = [Dog alloc] init]; Person * xiaoXi N = [[Person alloc] init]; [xiaoXin setDog: xiaoBai]; // The reference count is 2 NSLog (@ "count = % lu", xiaoBai. retainCount); [xiaoBai release]; // This setting is incorrect, because when the dog is release in setDog:, // The reference count is 0, dog is destroyed and cannot be retaken. [XiaoXin setDog: xiaoBai]; [xiaoXin release]; // In addition, it must be noted that both the class and the class must comply with memory management.
3.4 @ property retain, assign, copy expand
I.) retain expand
In the above Code, the setter and getter methods of Person can also be written as follows using property:
@ Property (nonatomic,Retain) Dog * dog;
There is no problem with the above tests.
Therefore, if we write @ property (nonatomic,Retain) Dog * dog ;,
It will be shown as follows:
- (void)setDog:(Dog *)dog { if (_dog != dog) { [_dog release]; _dog = [dog retain]; } } - (Dog *)dog { return _dog; }
Ii.) assign Expansion
@ Property (nonatomic,Assign)Dog * dog;, assign is a direct copy,
It will be shown as follows:
- (void)setDog:(Dog *)dog { _dog = dog; } - (Dog *)dog { return _dog; }
Iii.) copy Expansion
@ Property (nonatomic,Copy) Dog * dog;, copy, copy,
Copy the original object as follows:
- (void)setDog:(Dog *)dog { if (_dog != dog) { [_dog release]; _dog = [dog copy]; } } - (Dog *)dog { return _dog; }
3.5 string Memory Management
I.) string Memory Management
Strings do not follow the golden rule! (If we look at the string reference count, it's a mess !) This is just a representation! Actually, it is internal !!
What we need to do is that we still follow our golden law!
NSString * str = [[NSString alloc] initWithFormat: @ "% d % s", 1, "hello"]; NSLog (@ "count1 = % lu", str. retainCount); NSString * str2 = @ "hello"; NSLog (@ "count2 = % lu", str2.retainCount); NSString * str3 = [str retain]; NSString * str4 = [str2 retain]; NSLog (@ "count3 = % lu", str. retainCount); NSLog (@ "count4 = % lu", str2.retainCount); NSString * str5 = [[NSString alloc] initWithString: str]; NSString * str6 = [[NSSt Ring alloc] initWithString: str2]; NSLog (@ "count5 = % lu", str5.retainCount); NSLog (@ "count6 = % lu", str6.retainCount ); // NSString * str7 = [NSString stringWithFormat: @ "% d", 5]; [str release]; [str3 release]; [str4 release]; [str5 release]; [str6 release]; // str7 does not need release !!
Therefore, if it is NSString, our property format is written as follows: @ property (nonatomic,Copy)NSString * name;
Ii.) copy and mutableCopy
NSMutableString * string = [[NSMutableString alloc] initWithString: @ "hello"]; // This write will crash. If you look at the object, no pointer will be read. // copy will (mutable or immutable) copy a string to an immutable string. string2 is actually an immutable string // NSMutableString * string2 = [string copy]; // [string2 appendString: @ "world"]; NSString * string2 = [string copy]; NSLog (@ "string2 = % @", string2); // mutableCopy (variable or immutable) copy string to variable string NSMutableString * string3 = [string2 mutableCopy]; [string3 appendString :@ "World"]; NSLog (@ "string3 = % @", string3); // you do not need to worry about the reference count of the string, we can follow our own golden law to [string release]; [string2 release]; [string3 release]; // do not print retainCount In the UI, every user cares about each user // new is equivalent to alloc init, which is almost unnecessary in OC or IOS !!
3.6 Array Memory Management
Int main (int argc, const char * argv []) {@ autoreleasepool {Dog * dog1 = [[Dog alloc] init]; dog * dog2 = [[Dog alloc] init]; Dog * dog3 = [[Dog alloc] init]; Dog * dog4 = [[Dog alloc] init]; NSLog (@ "dog1.retainCount = % lu", dog1.retainCount); NSMutableArray * array = [NSMutableArray arrayWithObjects: dog1, dog2, dog3, dog4, nil]; NSLog (@ "dog1.retainCount = % lu", dog1.retainCount); [array addObject: dog1]; NSLog (@ "dog1.retainCount = % lu", dog1.retainCount ); // NSLog (@ "array = % @", array); [array removeLastObject]; NSLog (@ "dog1.retainCount = % lu", dog1.retainCount ); // The new array is not alloc new..., we do not need release // [array release]; NSLog (@ "dog1.retainCount = % lu", dog1.retainCount); [dog1 release]; [dog2 release]; [dog3 release]; [dog4 release];} // for @ autoreleasepool return 0 ;}
Conclusion
1) when we create an array, the array will reference each object and Add 1
2) When the array is destroyed, the array will reference each object minus 1.
3) when we add an object to the array, we will add 1 to the reference count of the object.
4) When we delete an object from an array, the reference count of the object is reduced by 1.
In short, you can manage yourself by who pollutes and who manages it.
3.7 autorelease and autoreleasepool
Autoreleasepool is an object
Autorelease is a method
Write the following code in the main function:
Int main (int argc, const char * argv []) {@ autoreleasepool {Dog * dog = [[Dog alloc] init]; // The dog is not destroyed immediately, instead, the destroy is delayed. // The dog object ownership is handed over to autoreleasepool [dog autorelpool]; // This can be printed because after printing the reference count of the dog, // destroy @ autoreleasepool {[dog autorelease]} NSLog (@ "retainCount = % lu", dog. retainCount);} NSLog (@ "the program is about to exit"); return 0 ;}
Note:: Autoreleasepool is equivalent to an array. If an object sends the autorelease message, the ownership of the object is actually handed over to autoreleasepool. When autoreleasepool is destroyed, A release message will be sent to all objects in the autoreleasepool.
3.8 Memory Management
The objects created by using the add method do not need to be release because autorelease is used for internal implementation of the class to delay release.
Add an addition method to the declaration of the Dog class.
+ (Id) dog;
Implementation in the implementation of the Dog class
+ (Id) dog
{
/* Note: Do not write release here. If it is release, it will be destroyed when it is just created,
With autorelease, the ownership of the object is handed over to the automatic release pool,
As long as the automatic release pool is not destroyed, the dog object will not be destroyed. */
Return [[[Dog alloc] init] autorelease];
}
The code in the main function is as follows:
int main(int argc, const char * argv[]) { @autoreleasepool { Dog *dog = [[[Dog alloc] init] autorelease]; Dog *dog1 = [Dog dog]; NSLog(@"count = %lu",dog.retainCount); NSLog(@"count1 = %lu",dog1.retainCount); } }