Structure: simply a two-way linked list, each linked list end to end. Each time a pool is created, a sentinel object is created at the head as a marker. There will be a next pointer at the top of the outermost pool. When the list is full, it’s at the top of the list and points to the next list.

1. Overview of Autorelease

When an AutoRelease message is sent to an object, Cocoa puts a reference to that object into the latest automatic release pool. It is still a valid object, so other objects in the scope defined by the autorelease pool can send messages to it. When the automatic release pool is released, all managed objects receive a “release” message, and all objects in the pool are released. Note that the same object can be called “autoRelease” multiple times and can be placed in the same “AutoreleasePool”. Therefore, by introducing the automatic release pool mechanism, the “autoRelease” method of an object instead of the “relrease” method can extend its life cycle and release directly to the current “AutorelreasePool”.

Many people say that the auto-release pool is released when the program executes at the end of scope (when the current scope braces end), which is not true. What is the correct process?

The iOS runtime is made up of runloops, each of which performs some of the steps shown below:




As you can see, each runloop creates an Autorelease Pool and releases it at the end of the runloop, so in general,
Each object that receives an AutoRelease message is released before the next runloop begins.





That is, during execution in a synchronized piece of code, the generated object receives
After an autoRelease message, it is generally not released before the end of the scope.


So, strictly speaking, in
Without manually adding an Autorelease Pool, the Autorelease object is released at the end of the current Runloop iteration, which is possible because the system adds automatic release pools Push and Pop to each runloop iteration.



2. AutoreleasePool and RunLoop

  • The App starts, apple registered in the main thread RunLoop two Observer, the callback is _wrapRunLoopWithAutoreleasePoolHandler ().

  • The first Observer monitors an event called Entry(about to enter Loop), which creates an automatic release pool within its callback by calling _objc_autoreleasePoolPush(). Its order is -2147483647, the highest priority, ensuring that the release pool is created before all other callbacks.

  • The second Observer monitors two events: calling _objc_autoreleasePoolPop() and _objc_autoreleasePoolPush() while waiting (ready to sleep) torelease the old pool and create a new one; _objc_autoreleasePoolPop() is called upon Exit(about to Exit the Loop) torelease the automatic release pool. The order of this Observer is 2147483647, the lowest priority, ensuring that its release pool occurs after all other callbacks.

The code that executes on the main thread is usually written inside such callbacks as event callbacks and Timer callbacks. These callbacks are surrounded by AutoreleasePool created by RunLoop, so there is no memory leak and the developer does not have to show that the Pool was created.





Methods that start with methods like alloc, copy, init,mutableCopy, and new, all return



retained return value, for example [[NSString alloc] initWithFormat:],


while
The rest of theIt is
unretained return value



For the former, the caller is responsible for releasing, while the latter is not responsible for releasing





The latter ARC extends the life of the objectMake sure the caller gets the return value and uses it, but autoRelease is not always used, only in worst case cases, so the caller can’t assume that the return value is actually in the AutoRelease pool. This is also understandable from a performance perspective. If we knew how long an object should live, we wouldn’t need to use AutoRelease. We could just use Release. If many objects use autoRelease, the entire pool can degrade its performance at drain.


Summary: 1. Temporary variables in a method are released using AutoReleasepool

2.NSCFString can be freed just like ordinary objects

3. The factory method of NSString and NSArray can prolong the life of objects (the same is true of NSDictionary, if you are interested).


The NSAutoreleasePool object is no longer allowed under ARC, and according to the official documentation, @Autoreleasepool is more efficient than it is, so only @Autoreleasepool is discussed here.

The two most important entry functions are as follows:

void *
objc_autoreleasePoolPush(void)
{
    return AutoreleasePoolPage::push();
}

void
objc_autoreleasePoolPop(void *ctxt)
{
    AutoreleasePoolPage::pop(ctxt);
}
Copy the code

Push inserts a tag into the poolPage, and POP sends a release message to all objects in the range.

There is a saying that:

In the child thread, the release operation is performed at the end of each run loop

On the main thread, the current runloop, you can see that several observer Activities = 0x1 are registered, corresponding to kCFRunLoopEntry; Activities = 0 xa0, corresponding is kCFRunLoopBeforeWaiting | kCFRunLoopExit their callback function for _wrapRunLoopWithAutoreleasePoolHandler (), This function calls push() on Entry, pop() and push() on beforeWaitting, and pop on exit

conclusion

Autoreleasepool {} Copies the codeCopy the code

Is equivalent to

void *context = objc_autoreleasePoolPush(); // the code in {} is objc_autoreleasePoolPop(context);Copy the code

Objc_autoreleasePoolPop () is called every time {} is emitted, so it is released directly.





The OC’s memory management decrement the reference count by one whenever it encounters a release and an autorelease, and if the object’s count becomes zero, it is destroyed by the system.