preface
The chapters in memory management also have an AutoreleasePool, which is a memory reclamation mechanism where objects placed in the AutoreleasePool are released late. So what is this auto-release pool and what are its features? We’ll take a closer look at it below
Structure analysis
-
Autoreleasepool (@autoreleasepool) in main.m
In C++ source, @autoreleasepool is an __autoreleasepool constructor. A search for AtAutoreleasePool shows the following code:
struct __AtAutoreleasePool { __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush(a); } ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj); }void * atautoreleasepoolobj; }; Copy the code
- By looking at the structure, you can see that it is called in the constructor
objc_autoreleasePoolPush
Is called when it is destructedobjc_autoreleasePoolPop
, coupled withOC
Breakpoints and assembly, and finally determine the code inlibobjc.A.dylib
, so inObjc4-818.2 -
Source code analysis of the core code
- By looking at the structure, you can see that it is called in the constructor
-
Objc_autoreleasepoolpage (push) and objC_AutoreleasepoolPage (pop);
void * objc_autoreleasePoolPush(void) { return AutoreleasePoolPage::push(a); }void objc_autoreleasePoolPop(void *ctxt) { AutoreleasePoolPage::pop(ctxt); } Copy the code
Let’s look at AutoreleasePoolPage
AutoreleasePoolPage
-
- find
AutoreleasePoolPage
You can see the comment at the beginning of the method:
- In the comments, you can see that the auto-release pool holds Pointers to either objects or to the boundaries of the release pool
POOL_BOUNDARY
There’s another one in the poolThe sentry object
The auto release pool is oneTwo-way linked list
.
- find
-
AutoreleasePoolPage
Has its own constructor and destructor:
AutoreleasePoolPageData
-
AutoreleasePoolPage inherits AutoreleasePoolPageData, which is a structure
The parameters are described as follows:
magic
: used for verificationAutoreleasePoolPage
Is the structure completenext
: indicates the latest additionautoreleased
The next position of the object, that’s what this object was initialized tobegin()
thread
: points to the current threadparent
: refers to the parent node, the first nodeparent
A value ofnil
child
: refers to the child node, the last nodechild
A value ofnil
depth
: represents depth, from0
It starts to increase backwards1
. So each additional page increases1
hiwat
Representative:high water mark
, the maximum number of stacks
-
The AutoreloeasePool structure is analyzed in the code below
The code analysis
-
Create an empty project, change the environment to MRC, add objects to @Autoreleasepool, and print autoreleasePool:
extern void _objc_autoreleasePoolPrint(void); int main(int argc, char * argv[]) { @autoreleasepool { NSObject *obj = [[NSObject alloc] autorelease]; _objc_autoreleasePoolPrint(); } return 0; } Copy the code
-
_objc_autoreleasePoolPrint
Is in theobjc
The source is a function that prints the contents of the auto-release pool.
-
@autoreleasepool
Is the automatic release pool,autorelease
Is to add an object to the automatic release pool
-
-
The print result is as follows:
- You can observe the automatic release pool in front of
56 bytes
Initializes a member variable associated with, and then has a8 bytes
theThe sentry object
, before objects are added to the auto-release pool.
- You can observe the automatic release pool in front of
Home Page Structure
-
Based on the above analysis, the structure of the first page of autoreleasePool is shown below
How does the auto-release pool add destruction objects, how many destruction objects can be added to a page, and when objects are released? We will examine these properties in principle
The principle of
push
-
Let’s start with the push code
static inline void *push(a) { id *dest; if (slowpath(DebugPoolAllocation)) { // Each autorelease pool starts on a new pool page. dest = autoreleaseNewPage(POOL_BOUNDARY); } else { dest = autoreleaseFast(POOL_BOUNDARY); } ASSERT(dest == EMPTY_POOL_PLACEHOLDER || *dest == POOL_BOUNDARY); return dest; } Copy the code
Without looking at the Debug code, you can locate the autoreleaseFast code
-
The autoreleaseFast code is as follows:
static inline id *autoreleaseFast(id obj) { AutoreleasePoolPage *page = hotPage(a);/ / get hotpage if(page && ! page->full()) { // If the page exists and is not full, add the object return page->add(obj); } else if (page) { // If the storage is full, it will be added return autoreleaseFullPage(obj, page); } else { // If page does not exist, create page return autoreleaseNoPage(obj); }}Copy the code
- from
hotPage
Get to thepage
The latter is mainly divided into three situations:-
page
If it exists and is not full, add
-
page
If it is full, it callsautoreleaseFullPage
Method added after paging
-
page
Call if it does not existautoreleaseNoPage
Perform related creation and add operations
-
The following is a detailed analysis of the three cases
- from
add
-
At the heart of the ADD code is a memory shift operation
next
The pointer starts out pointingbegin
Position, when one comes inobj
.next
It’s going to shift it down by one until it’s fullnext
The pointer translation process is shown as follows:
The judgment is full
-
First let’s look at the condition full:
- when
next
Point to theend
The position, which is 1, 2, 3page
And at the end of that, it’s full, you can see thatsize
The maximum value of2 ^ 12
That is4096
, because the inside member variables account for56
Bytes, the sentinel object accounted for8 bytes
, so you can add the object account4032
Bytes, that is, can be added504
Destroy the object.
- when
-
Code verification:
-
When the 505th is added it is paginated and printed as follows
- The first
505
Three objects were added to the newpage
In the newpage
Does not have a member variable that handles initialization needsThe sentry object
, that is, new page occupancy4040
It’s a byte, which isCan be stored505
An object
- The first
-
Question: why is there no sentinel object on page 2?
- A: Because the sentry object has “monitoring”
page
Boundary function, the first page is already full is not neededadd
Operation, so it can go to the second page to work, because it will work on the current page until it is full, so only one sentinel object is enough
- A: Because the sentry object has “monitoring”
-
Conclusions: 1. The first page can store a maximum of 504 objects, and the new page can store a maximum of 505 objects. 2. The new page has no sentinel object
autoreleaseFullPage
-
When full, the autoreleaseFullPage method is used
- Here is mainly
do-while
Find the last one in the looppage
- If not, will
page
Set tohot
Call again,add
addobj
- If it is full, it is called
AutoreleasePoolPage
Create a newpage
And thenadd
addobj
.
- If not, will
- Here is mainly
-
The AutoreleasePoolPage method initializes the page and sets the value of the member variable, and if there is a parent, sets the parent’s child as itself
autoreleaseNoPage
-
HotPage is created when no hotPage is retrieved, i.e. the first hotPage does not exist:
- The creation process is the same as the full one above, but one will be added after the first interface is created
The sentry object
, and then add the destruction object
- The creation process is the same as the full one above, but one will be added after the first interface is created
pop
-
The main code for POP is as follows
- if
token
Point to the sentinel object, indicating that the first page is empty, and do something about it popPageDebug
The method will eventually go topopPage
Function, and look againpopPage
The implementation of the
- if
popPage
The following code
-
popPage
It first callsreleaseUntil
Apply the object torelease
:
- This code is mainly in the
The while loop
To fetch the object and then callobjc_release
Method to release - The process of translating objects is shown as follows:
-
- Object is released and the current page is empty
parent
And then put the current pagekill
And willparent
Set tohotPage
- Object is released and the current page is empty
-
- If it is
page
If it’s the first page, it’s directkill
And willhotPage
Set tonil
- If it is
-
- If the current
page
There arechild
:
- If the current page is half full, the
child
directlykill
- if
child
There arechild
, it willchild
thechild
directlykill
- If the current
kill
-
The core of page destruction is the kill function, which is implemented as follows:
kill
, the process is relatively simple, is to get the current pagechild
Start with the last onepage
startdelete
, until the current page
The entire POP process is to first destroy the object release and then delete from the last one until the first one. The first page destroys release and sets hotPage to nil
Multi-page structure diagram
Related topics
-
AutoreleasePool
Can it be nested?
- The code tests are as follows
int main(int argc, char * argv[]) { @autoreleasepool { NSObject *obj1 = [[NSObject alloc] autorelease]; NSLog(@"obj1 : %@", obj1); @autoreleasepool { NSObject *obj2 = [[NSObject alloc] autorelease]; NSLog(@"obj2 : %@", obj2); _objc_autoreleasePoolPrint(); } _objc_autoreleasePoolPrint(); } return 0; } Copy the code
- Print result:
-
As you can see from the result, there are two sentinels in the first print, that is, the contained autorelease pool is pushed into the outer autorelease pool, so there are two sentinels in the print, and when out of scope, the inner autorelease pool is freed, so there is only one sentinel and obj1 in the print below.
-
A: Auto release pools can be nested
-
ARC
How are objects added to the auto-release pool?
- We know that
MRC
In, the created object needs to be appendedautorelease
Before you can go into the poolARC
There is noautorelease
, you can use__autoreleasing
Modifier to add an object to an automatic release pool:
int main(int argc, char * argv[]) { @autoreleasepool { NSObject *obj1 = [NSObject alloc] ; NSLog(@"obj1 : %@", obj1); NSObject * __autoreleasing obj2 = [NSObject alloc] ; NSLog(@"obj2 : %@", obj2); _objc_autoreleasePoolPrint(); } return 0; } Copy the code
The print result is as follows:
ARC
There are mainly the following situations when entering the pool:If it is notalloc/new/copy/mutableCopy
Automatically registers the returned object toAutoreleasepool