Implementation principle of Objective-C Autorelease Pool
Memory Management has always been one of the key and difficult points for learning Objective-C. Although it is already in the ARC era, it is still necessary to understand the memory management mechanism of Objective-C. Among them, figuring out the principles of autorelease is even more important. Only by understanding the principles of autorelease can we truly understand the Objective-C memory management mechanism. Note: The runtime source code used in this article is the latest version.objc4-646.tar.gz
.
When will the autoreleased object be released?
Autorelease is essentially a delay in calling release. When will the autoreleased object be released? To solve this problem, we will first make a small experiment. This small experiment is divided into three scenarios. Please first think about console output in each scenario to deepen your understanding. Note: the source code of this experiment can be found in AutoreleasePool.
12345678910111213141516171819202122232425262728293031323334 |
_ Weak NSString * string_weak _ = nil;-(void) viewDidLoad {[super viewDidLoad]; // scenario 1 NSString * string = [NSString stringWithFormat: @ leichunfeng]; string_weak _ = string; // scenario 2 // @ autoreleasepool {// NSString * string = [NSString stringWithFormat: @ leichunfeng]; // string_weak _ = string; //} // scenario 3 // NSString * string = nil; // @ autoreleasepool {// string = [NSString stringWithFormat: @ leichunfeng]; // string_weak _ = string; //} NSLog (@ string: % @, string_weak _);}-(void) viewWillAppear :( BOOL) animated {[super viewWillAppear: animated]; NSLog (@ string: % @, string_weak _);}-(void) viewDidAppear :( BOOL) animated {[super viewDidAppear: animated]; NSLog (@ string: % @, string_weak _);}
|
How did you think? I believe you have an answer in your mind. Let's take a look at the console output:
1234567891011121314 |
// Scenario 12015-05-30 10:32:20. 837 AutoreleasePool [33876: 1448343] string: leichunfeng2015-05-30 10:32:20. 838 AutoreleasePool [33876: 1448343] string: leichunfeng2015-05-30 10:32:20. 845 AutoreleasePool [33876: 1448343] string: (null) // scenario 22015-05-30 10:32:50. 548 AutoreleasePool [33915: 1448912] string: (null) 10:32:50. 549 AutoreleasePool [33915: 1448912] string: (null) 10:32:50. 555 AutoreleasePool [33915: 1448912] string: (null) // scenario 32015-05-30 10:33:07. 075 AutoreleasePool [33984: 1449418] string: leichunfeng2015-05-30 10:33:07. 075 AutoreleasePool [33984: 1449418] string: (null) 10:33:07. 094 AutoreleasePool [33984: 1449418] string: (null)
|
Are there any differences with the expected results? Any way. Let's take a look at why we get this result.
Analysis: In three scenarios, we use[NSString stringWithFormat:@leichunfeng]
An autoreleased object is created, which is the prerequisite for our experiment. In addition, in orderviewWillAppear
AndviewDidAppear
To continue accessing this object, we use a global__weak
Variablestring_weak_
To point to it. Because__weak
One feature of a variable is that it does not affect the lifecycle of the object to which it points. Here we use this feature.
Scenario 1: When used[NSString stringWithFormat:@leichunfeng]
When an object is created, the reference count of this object is 1, and the object is automatically added to the current autoreleasepool. When using local variablesstring
When pointing to this object, the reference count of this object + 1 is changed to 2. Because under ARCNSString *string
Essentially__strong NSString *string
. ThereforeviewDidLoad
Before the method is returned, this object always exists and the reference count is 2. WhenviewDidLoad
Local variables when the method returnsstring
Recycled, pointingnil
. Therefore, the reference count of the object to which it points is-1, which is 1.
InviewWillAppear
Method, we can still print the value of this object, indicating that this object has not been released. Isn't that scientific? If I read less books, you lie to me. Isn't it always said that when the function returns, the objects generated inside the function will be released? If you think like this, I can only say: Sao Nian, you have been so old. Just kidding. Let's continue. As mentioned above, this object is an autoreleased object. The autoreleased object is added to the latest autoreleasepool. Only when the autoreleasepool is drain, the autoreleased object in the autoreleasepool will be release.
In addition, we note that whenviewDidAppear
When this object is printed, the object value becomesnil
The object has been released. Therefore, we can make a bold guess that this object must be inviewWillAppear
AndviewDidAppear
Methods are released at some time, and because the autoreleasepool in which it is located is released when it is drain.
What are you talking about? You can prove to me that your mom is your mom. Well, I can't prove it, but I can still prove it from the above guesses. Don't believe it, you see!
Before we start, I will briefly describe the principle. We can uselldb
Ofwatchpoint
Command to set observation points and observe global variablesstring_weak_
,string_weak_
The variable stores the address of the autoreleased object we created. Here, we use__weak
Another feature of a variable is that when the object it points to is released,__weak
The variable value is setnil
. After understanding the basic principles, we began to verify the above guesses.
We will first open a breakpoint in line 3. When the program runs to this breakpoint, we willlldb
Commandwatchpoint set v string_weak_
Set observation points and observestring_weak_
Variable value changes. As shown in, we will see similar output in the console, indicating that we have successfully set an observation point:
After setting the observation point, clickContinue program execution
To continue running the program, we will see the interface shown in:
Let's take a look at the output in the console.string_weak_
The variable value is composed0x00007f9b886567d0
Changed0x0000000000000000
, That isnil
. This indicates that the object it points to is released. In addition, we can also note that the value of the object is printed twice on the console.viewWillAppear
It has also been called, andviewDidAppear
Not called yet.
Next, let's look at the thread stack on the left. We see a very sensitive method call.-[NSAutoreleasePool release]
, This method is finally calledAutoreleasePoolPage::pop(void *)
Function to perform the release operation on the autoreleased object in the autoreleasepool. Based on the previous analysis, we know thatviewDidLoad
The autoreleased object created in this operation has a reference count of 1 after the method is returned. Therefore, after the release operation, the reference count of this object-1 is changed to 0, the autoreleased object is finally released, and you can guess it.
In addition, we did not manually add autoreleasepool in the Code. Where did the autoreleasepool come from? After reading the subsequent chapters, you will understand.
Scenario 2: Similarly, when[NSString stringWithFormat:@leichunfeng]
When an object is created, the reference count of this object is 1. When using local variablesstring
When pointing to this object, the reference count of this object + 1 is changed to 2. When the current scope exists, local variablesstring
Changednil
So the reference count of the object to which it points is 1. In addition, we know that@autoreleasepool {}
The current autoreleasepool is drain, and the autoreleased object is release. Therefore, the reference count of this object is 0, and the object is finally released.
Scenario 3: Similarly, when@autoreleasepool {}
The autoreleased object is release, and the reference count of the object is changed to 1. When a local variable is generatedstring
Scope, that isviewDidLoad
When the method returns,string
Pointednil
The reference count of the object to which it points is 0, and the object is finally released.
Understanding when the autoreleased object is released in these three scenarios is very helpful for us to understand the Objective-C memory management mechanism. Among them, scenario 1 appears most frequently, that is, we do not need to manually add@autoreleasepool {}
Directly use the autoreleasepool maintained by the system. Scenario 2 requires manual addition.@autoreleasepool {}
Manually intervene in the release time of the autoreleased object. Scenario 3 is introduced to distinguish scenario 2. In this scenario@autoreleasepool {}
Scope when the autoreleased object is released.
PS: Please refer to the analysis process in scenario 1 and uselldb
Commandwatchpoint
Verify the release time of the autoreleased object in scenario 2 and scenario 3 by yourself. you should give it a try yourself.
AutoreleasePoolPage
Careful readers should have noticed that we have mentioned above-[NSAutoreleasePool release]
The method is ultimately calledAutoreleasePoolPage::pop(void *)
Function to perform the release operation on the autoreleased object in the autoreleasepool.
What is AutoreleasePoolPage? In fact, autoreleasepool does not have a separate memory structure. It is implemented through a bidirectional linked list with AutoreleasePoolPage as the node. Open the source code project of runtimeNSObject.mm
The source code of autoreleasepool can be found in lines 438th-932 of the file. By reading the source code, we can know: