autoreleasepool - ShenYj/ShenYj.github.io GitHub Wiki
在 ARC 模式下,@autoreleasepool
已经很少被使用了
其对应的是一个 C++
结构体对象 __AtAutoreleasePool
, 可通过编译成 C++
代码查阅
struct __AtAutoreleasePool {
// 构造函数
__AtAutoreleasePool() { atautoreleasepoolobj = objc_autoreleasePoolPush(); }
// 析构函数
~__AtAutoreleasePool() { objc_autoreleasePoolPop(atautoreleasepoolobj); }
void * atautoreleasepoolobj;
};
在程序入口 main
函数中默认包含一个 @autoreleasepool
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
-
最终会创建一个
__AtAutoreleasePool
实例 -
并在创建的时候自动调用
objc_autoreleasePoolPush()
函数-
内部调用
AutoreleasePoolPage::push()
static inline void *push() { 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; }
-
-
在销毁的时候自动调用
objc_autoreleasePoolPop(atautoreleasepoolobj)
函数-
内部调用
AutoreleasePoolPage::pop(ctxt)
static inline void pop(void *token) { AutoreleasePoolPage *page; id *stop; if (token == (void*)EMPTY_POOL_PLACEHOLDER) { // Popping the top-level placeholder pool. page = hotPage(); if (!page) { // Pool was never used. Clear the placeholder. return setHotPage(nil); } // Pool was used. Pop its contents normally. // Pool pages remain allocated for re-use as usual. page = coldPage(); token = page->begin(); } else { page = pageForPointer(token); } stop = (id *)token; if (*stop != POOL_BOUNDARY) { if (stop == page->begin() && !page->parent) { // Start of coldest page may correctly not be POOL_BOUNDARY: // 1. top-level pool is popped, leaving the cold page in place // 2. an object is autoreleased with no pool } else { // Error. For bincompat purposes this is not // fatal in executables built with old SDKs. return badPop(token); } } if (slowpath(PrintPoolHiwat || DebugPoolAllocation || DebugMissingPools)) { return popPageDebug(token, page, stop); } return popPage<false>(token, page, stop); }
-
可以看出来,自动释放池的主要结构就是
AutoreleasePoolPage
-
AutoreleasePoolPage
class AutoreleasePoolPage : private AutoreleasePoolPageData { magic_t const magic; __unsafe_unretained id *next; // 指向存放下一 个 autorelease 对象的地址 pthread_t const thread; AutoreleasePoolPage * const parent; // 指向上一个 `AutoreleasePoolPage` AutoreleasePoolPage *child; // 指向下一个 `AutoreleasePoolPage` uint32_t const depth; uint32_t hiwat; };
AutoreleasePoolPage
主要是提供了大量的静态函数,成员都是继承自父类AutoreleasePoolPageData
-
每个
AutoreleasePoolPage
会占用4096字节(4K)
大小,除了用来存放它的内部成员变量(56字节
),剩下的空间(4040字节
)用来存放autorelease
对象的地址 -
所有的
AutoreleasePoolPage
对象通过双向链表的形式连接在一起 -
初始化一个
AutoreleasePoolPage
调用push
函数时,首先会将一个POOL_BOUNDARY
入栈,返回其存放的内存地址, 也就是在成员变量后插入一个nil
,返回存放的内存地址给atautoreleasepoolobj
define POOL_BOUNDARY nil
-
接下来再向
autoreleasepool
中存放对象时,就会按顺序存储对象的地址 -
如果当前
AutoreleasePoolPage
被存满,会再次新建一个AutoreleasePoolPage
继续存储 -
当
autoreleasepool
大括号结束需要释放内存时,会调用objc_autoreleasePoolPop
函数并将atautoreleasepoolobj
作为参数传过去,atautoreleasepoolobj
存放的是POOL_BOUNDARY
地址, 从后向前执行pop
移除对象直到POOL_BOUNDARY