When learning objective-C, it is easy for beginners to get confused about the memory management part. A major reason is that the reference counting principle is not clear, I cannot understand the reference quantity of objects, so that the object's memory cannot be completely released. The apple official documentation on memory management is very simple and has only three principles:
- When you create an object using the new, alloc, or copy method, the reserved pointer of this object is 1. When you no longer use this object, you should want this object to send a release or autorelease message, so that the object will be destroyed at the end of its life.
- When you obtain an object through other methods, assuming that the reserved counter of the object is 1 and has been set to Auto Release, you do not need to perform any operations to ensure that the object is destroyed. If you want to own this object for a period of time, you need to keep it and make sure it is released when the operation is complete.
- If you retain an object, You Need To (eventually) release it or automatically release it. Make sure that the retain method and the release method are used the same number of times.
If you follow these rules when writing code, you can avoid Memory leakage. However, if you write code by simply relying on the "Memory" of these rules, I am afraid I will not have a bottom in my mind, once you encounter a problem analysis problem, it is difficult to fundamentally find the cause of the problem. This article shares the analysis process of understanding the reference count, combined with the relevant graphics, we hope that you will have a deep understanding of the principle of object reference counting.
Encountered a problem? Analyze and test
What is the reference count of the current object?
Why do you want to raise this question? Many people will confuse the relationship between the number of pointers of objects and the number of references. If they do not understand this question, they will not understand the reference count of objects, of course, the memory cannot be correctly released. Before talking about this, let's take a look at the concepts of heap memory and stack memory,
- Stack memory: the compiler is responsible for allocating and storing the value of the basic variables defined in the local environment, such as the basic variables in the method. When the local environment is left, the compiler Automatically releases its memory space.
- Heap memory: Generally, it is manually allocated by the programmer through new or alloc. after use, the programmer needs to manually release the memory. If the programmer does not release the memory, it may be recycled by the OS at the end of the program. Note that it is different from the heap in the data structure.
The variable name is actually a symbolic address. During program compilation and connection, the system allocates a memory address to each variable name. In a program, you can find the corresponding memory address by using the variable name to read data from its storage unit. A pointer is a special variable because it stores the address of a variable. As shown in:
The above memory model I believe everyone knows that there is an indirect (Pointing) Relationship between the pointer and the object. Therefore, when the pointer points to an object, many people will think that this pointer references this object, and then they think that when the pointer points to an object, the reference count of this object will be increased by 1, this kind of understanding is a kind of perceptual understanding. In fact, for an object, it does not know how many pointers are directed to it. Its release only relies on reference counting. So what is reference counting? In objective-C, most objects are inherited from nsobject. nsobject contains a retaincount field used to save the referenced quantity. In other words, this field is the reference count. The nsobject class is defined as follows:
- (id)retain;
- (oneway void)release;
- (id)autorelease;
- (NSUInteger)retainCount;
- (NSString *)description;
Therefore, to facilitate understanding, we can simplify nsobject into the following model:
Whether an object can be released is used to determine whether its reference count is zero, that is, whether the retaincount field of the object is equal to 0, and the number of pointers to the object is irrelevant to the value of the retaincount field of the object, therefore, the number of pointers is not equal to the number of references. When the Pointer Points to this object, it only assigns a value to the pointer variable and does not modify the retaincount value of the object. Therefore, when the pointer points to an object, the reference count of this object remains unchanged.
The code above is used as an example. When we call the new method of the test object, the retaincount value is automatically set to 1. When we assign test1 to Test2, only a pointer value is assigned, and the retaincount value of the object is not modified. Therefore, the reference count remains unchanged and is still 1.
Test cases:
1 engine * engine1 = [engine new]; 2 nslog (@ "create an object engine1 through the new message :"); 3 // output the engine1 pointer address 4 nslog (@ "engine1 address is % P. ", engine1); 5 // output engine1 retaincount 6 nslog (@" engine1 retaincount is % lu ", (unsigned long) [engine1 retaincount]); 7 8 engine * engine2 = engine1; 9 nslog (@ "copy the pointer engine1 to the pointer engine2 :"); 10 // output the engine2 pointer address 11 nslog (@ "engine2 address is % P. ", engine2); 12 // output engine1 retaincount13 nslog (@" engine1 retaincount is % lu ", (unsigned long) [engine1 retaincount]); 14 // output engine2 retaincount15 nslog (@ "engine2 retaincount is % lu", (unsigned long) [engine2 retaincount]); 16 17 engine * engine3 = [engine1 retain]; 18 nslog (@ "Get engine3:" Through retain message); 19 // output engine3 pointer address 20 nslog (@ "engine3 address is % P. ", engine3); 21 // output engine1 retaincount22 nslog (@" engine1 retaincount is % lu ", (unsigned long) [engine1 retaincount]); 23 // output engine2 retaincount24 nslog (@ "engine2 retaincount is % lu", (unsigned long) [engine2 retaincount]); 25 // output engine3's retaincount26 nslog (@ "engine3 retaincount is % lu", (unsigned long) [engine3 retaincount]); 27 28 [engine2 release]; 29 nslog (@ "Send message release to engine2"); 30 nslog (@ "engine2 address is % P. ", engine2); 31 nslog (@" engine2 retaincount is % lu. ", (unsigned long) [engine2 retaincount]);
The output result is as follows:
The following conclusions can be drawn from the output:
- Like the results obtained from the analysis at the beginning of this article, the reference count of an object cannot be changed through pointer assignment.
- Whether getting objects through pointer assignment or retain, they all point to the same memory address, that is, to the same object
- Before the reference count of an object is zero, all pointers to it are available. Sending a release message through a pointer only removes the reference count by one, and the pointer itself will not be destroyed.
Because the output reference count is required, arc is not used, so there is a small problem, that is, when you exit the local environment, even if the object pointed to by the local pointer has been destroyed, the value of the local pointer variable remains unchanged. Therefore, you must manually assign a value to nil. If arc is used, the memory is automatically reclaimed and the pointer is assigned to nil.
Summary
No matter whether you use pointer assignment or retain or copy to keep the object, the number of pointers pointing to the object is increased. These pointers all point to the same memory address, because the memory address allocated by the object remains unchanged.
The number of pointers to an object does not have any relationship with the reference count, but the reference count of an object can be changed through retain, copy, or release.
Only when the reference count is 0 will the memory space occupied by the object be released.
Ah, it's really a "heartless", even if more Pointers "fall in love with objects", people will only recognize reference counts in their lives.