Currently, memory management is all about automatically managing reference counts of objects in an ARC environment. Let’s take a look at autoReleasepool.

1.autoreleasepool

1.1 release and autorelease

The reference count is immediately reduced by one when the release method is called. When an object calls the autoRelease method, its reference count is reduced by one at a later time, usually in the next “event loop” in the current thread. The autoRelease method is especially useful when a method returns an object. If an object created in a method is released before it is returned, it is possible that the object will be destroyed before it is returned. With autoRelease, the object is guaranteed to be alive when it is returned, and there is no need for the caller to manually release the object, since the reference count of the object is automatically reduced by 1 in the next event loop of the current thread. Autorelease extends the life of the object, surviving for a period of time beyond the bounds of the method call.

1.2 Automatic Release Pool

1. There are two ways to release an object. One is to call the release method, and the object reference count that calls the Release method is immediately decreased. The other option is to call the autoRelease method to add an object to the “autorelease pool”. The objects in the autorelease pool will be released at a later time. When the autorelease pool is emptied, the system will send a release message to the objects in the pool. 2. The auto-release pool is created in the open curly bracket and automatically emptied at the right curly bracket. Objects within the curly bracket will receive a release message at the end of the curly bracket. 3. Automatic release pooling reduces application memory spikes. 4. We don’t need to worry about the creation of auto-release pools. By default, threads created by the main thread or GCD have an automatic release pool that is emptied every time an event loop is executed

1.3 Clang analysis

int main(int argc, const char * argv[]) {

    @autoreleasepool {

        // insert code here...

        NSLog(@"Hello, World!");

    }

    return 0;

}
Copy the code

The main function adds our code to autoReleasepool and Clang results in the following:

int main(int argc, const char * argv[]) {

    /* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool; 
        NSLog((NSString *)&__NSConstantStringImpl__var_folders_2f_kt02d2w10p55r2z7mn5gc7qw0000gn_T_main_904163_mi_0);

    }

    return 0;

}
/ * destructor * /
struct __AtAutoreleasePool {

  __AtAutoreleasePool(){atautoreleasepoolobj = objc_autoreleasePoolPush(); } ~__AtAutoreleasePool(){objc_autoreleasePoolPop(atautoreleasepoolobj); }void * atautoreleasepoolobj;

};
Copy the code

Autoreleasepool is an object, essentially.

  • __AtAutoreleasePoolIt’s a structure. It hasConstructor + destructorDestructor is automatically called when the scope ends for objects defined by the structure
  • Among them{}Is the scope, and the advantage isThe structure is clear and readable, you canCreate destroy in time

1.4 AutoreleasePoolPage

Take a look at the source description for AutoReleasepool

As we know from Clang, auto-release pool is a destructor that is called when constructing:objc_autoreleasePoolPush()Called when it is destructedobjc_autoreleasePoolPop()

The automatic release pool call is passedAutoreleasePoolPageWith apushandpop. The page size is 4096AutoreleasePoolPage is a class with a few methods and its own destructor. Some operations on the page are as follows:

AutoreleasePoolPageInheritance inAutoreleasePoolPageDataLet’s see

  • Magic is used to verify whether the structure of AutoreleasePoolPage is complete.

  • Next refers to the next location of the newly added Autoreleased object, initialized to begin();

  • Thread refers to the current thread.

  • Parent refers to the parent, and the first parent value is nil.

  • Child refers to a child, and the last child is nil;

  • Depth is the depth. It starts at 0 and increases by 1.

  • Hiwat represents the mark of maximum loading quantity of High water Mark

AutoreleasePoolPage -> AutoreleasePoolPageData -> AutoreleasePoolPage -> AutoreleasePoolPage From here, it can be shown that the autofree pool is not only a page, but also a bidirectional linked list structure.

2. objc_autoreleasePoolPush

Determine the currentWhether there is a release poolCreate one if there is none, push one if there isPOOL_BOUNDARY.

  • Continue to look atautoreleaseNewPage

  • To viewHotPage ()

  • To viewautoreleaseNoPageCreate a page

  • View the initialize auto release pool pageAutoreleasePoolPage

Among thembegin()Represents the position at which the object is pressed, representsAutoreleasePoolPageHis possession56The size of the

  • View automatic free pool memory structure

In an ARC environment, you cannot manually call autoRelease and switch Demo to MRC mode (Build Settings -> Objectice -c Automatic Reference Counting set to NO).

We press for loop into print auto release pool case

The address of the page0x7fbcc2810000And boundary address0x7fbcc2810038In hexadecimal 3 times 16 plus 8 is 56, which is exactlyAutoreleasePoolPageIts own memory size. We add 505 objects

The first page is stored504Object. Page 2 stores it1The second page no longer stores boundariesThe sentry. We continue the for loop with 1010 objects. The first pageThe second page

The third page

increased505Number of objects addedOne page, indicating that a page can store 505 objects505 * 8 = 4040Size, the page itself size is56So the size of a page is zero4096Same definition as red. Home page because of storageThe sentry objectsoStore one less object.

  • Pressure stack object autoreleaseFast

Enter theautoreleaseFastSource code, there are mainly the following steps:

  1. Gets the current action page and determines whether the page exists and is full
  2. If the pageExists and is not fullbyaddMethod to push objects
  3. If the pagePresent and fullbyautoreleaseFullPageMethod to schedule a new page
  4. ifPage does not existbyautoreleaseNoPageMethod to create a new page
  • autoreleaseFullPageAnalysis of the

  1. traverseChain of child pages of the current page until there are no child pagescreateA page
  2. Set the page to be created tohotPageThe operation page
  3. Add objects to the page you created,The pressure of stack.
  • autoreleaseAnalysis of the underlying

autorelease->rootAutorelease->rootAutorelease2->autorelease(id obj)

Ultimately it’s implementationautoreleaseFastPerform a stack operation and enter as a stack sentinel objectautoreleaseFastJust for different people.

3. objc_autoreleasePoolPop

There is a parameter in the objc_autoreleasePoolPop method. Clang analysis found that the parameter passed is the sentinel object returned after the push, CTXT. The purpose is to avoid stack clutter and prevent other objects from being pushed out of the stack to view the pop source code

  1. Empty page processing, andObtain the page based on the token
  2. Fault-tolerant processing
  3. throughpopPagePage out of the stack
  • popPageTo view

If not the sentry object passespopPage<false>(token, page, stop)Out of the stack operation, throughreleaseUntilUnstack the current operation page object and release it tostopAll objects before the position, and then determine whether the previous page is empty, related to the pagekill.

  • releaseUntilTo view

The while loop iterates through all objects up to the current stop object, except for the sentinelobjc_releaseAn off-stack operation, in which a nested while loop iterates over the previous parent page.

Enter thereleaseUntil

And then you go from the back pages, page by pageObjects in the Release pageUntil thestopObject, notThe sentry objectitrelease.

4. To summarize

1. The automatic release pool mainly manages the object memory for us. We do not need to release the object in the release pool manually, but release the object in the release pool in the next event cycle, which will delay the object life cycle. 2. The auto-release pool is an object with a destructor of its own. When it is created, it pushes the stack and when it is destructed, it pushes the stack. Inherited from the autorelseasePoolPage class, poolPage itself inherits from the autoreleasePoolPageData structure, which is 56 bytes in size. A POOL_Boundary is inserted after the page is created to prevent crossing the boundary, but only the first page is inserted with a sentinel object. A maximum of 505 objects can be inserted into a page. The size of the page is 505*8+56 (page size) = 4096 bytes. PoolPage is a bidirectionally linked list structure with one parent node and one child node. 3. The autorelseasePoolPage object is added through push. If there is no page, create the page and pass in the sentinel object. When the page is full, create a new page using autoreleaseNoPage and add objects using the Add method. 4. The pop method is usually called during the destructor, passing in the sentry object. According to the position of the stop object, we release all objects before the stop object, except the sentry object. Release the next object of the current page through the while loop. If the current page is empty, set hotPage to the parent page and repeat until the stop object.