3. AutoreleasePool源码解析
AutoreleasePool源码可以从Runtime源码中获得。下载好我们可以在NSObject.mm中看到AutoreleasePool的实现原理和结构说明:
Autorelease pool implementation
A thread's autorelease pool is a stack of pointers. Each pointer is either an object to release, or POOL_BOUNDARY which is an autorelease pool boundary.
A pool token is a pointer to the POOL_BOUNDARY for that pool. When the pool is popped, every object hotter than the sentinel is released.
The stack is divided into a doubly-linked list of pages. Pages are added and deleted as necessary.
Thread-local storage points to the hot page, where newly autoreleased objects are stored.
AutoreleasePool其实是一个存贮指针的栈,内部指针代表延迟释放的对象或者是表示不同AutoreleasePool之间的边界对象。
AutoreleasePool的token指针名为POOL_BOUNDARY,当AutoreleasePool执行Pop操作时后于POOL_BOUNDARY入栈的对象将被释放。
AutoreleasePool是由多页的双向列表页组成,列表页在必要时可添加与删除。
TLS(Thread-local storage)指向autoreleased最近存储的AutoreleasePool
class AutoreleasePoolPage
{
...
magic_t const magic; //校验AutoreleasePoolPage完整性
id *next; //存放下一个autoreleased对象地址
pthread_t const thread; //对应线程
AutoreleasePoolPage * const parent; //父AutoreleasePoolPage
AutoreleasePoolPage *child; //子AutoreleasePoolPage
uint32_t const depth; //当前AutoreleasePoolPage索引index
uint32_t hiwat; //存储autoreleased对象峰值数
...
}
接下来我们分析在使用@autoreleasepool block时代码的具体执行。我们先从每个Cocoa Touch工程都包含的Main.m文件入手,cd到Main.m路径下再通过命令行来将代码转成c++形式
clang -rewrite-objc -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.3.sdk main.m
我们可以看到原本的代码被转换成:
int main(int argc, char * argv[]) {
/* @autoreleasepool */ { __AtAutoreleasePool __autoreleasepool;
return UIApplicationMain(argc, argv, __null, NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("AppDelegate"), sel_registerName("class"))));
}
}
而结构体__AtAutoreleasePool的定义我们也可以在转换代码中找到:
struct __AtAutoreleasePool {
__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
void * atautoreleasepoolobj;
};
由此我们可以知道__AtAutoreleasePool结构体在初始化和析构时分别执行了objc_autoreleasePoolPush和objc_autoreleasePoolPop(atautoreleasepoolobj)函数。我们先从这两个函数开始分析:(函数源码可以在之前的NSObject.mm文件中查找到)
objc_autoreleasePoolPush(void)
void *objc_autoreleasePoolPush(void)
{
return AutoreleasePoolPage::push();
}
push()
static inline void *push()
{
id *dest;
if (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;
}
Debug模式
autoreleaseNewPage(POOL_BOUNDARY);
非Debug模式下
autoreleaseFast(POOL_BOUNDARY);
返回空池标志位或者AutoreleasePool边界对象 |