AutoReleasePool
AutoreleasePool的实现原理
@autoreleasePool = __AtAutoreleasePool __autoreleasePool
__AtAutoreleasePool 结构体
AutoreleasePool 是 oc 的一种内存回收机制,正常情况下变量在超出作用域的时候 release,但是如果将变量加入到 pool 中,那么release 将延迟执行
AutoreleasePool 并没有单独的结构,而是由若干个 AutoreleasePoolPage 以**双向链表**形式组成
1. PAGE_MAX_SIZE :4KB,虚拟内存每个扇区的大小,内存对齐
2. 内部 thread ,page 当前所在的线程,AutoreleasePool是按线程一一对应的
3. 本身的成员变量占用56字节,剩下的内存存储了调用 autorelease 的变量的对象的地址,同时将一个哨兵插入page中
4. pool_boundry 哨兵标记,哨兵其实就是一个空地址,用来区分每一个page 的边界
5. 当一个Page被占满后,会新建一个page,并插入哨兵标记
单个自动释放池的执行过程就是objc_autoreleasePoolPush() —> [object autorelease] —> objc_autoreleasePoolPop(void *)
具体实现如下:
void *objc_autoreleasePoolPush(void) {
return AutoreleasePoolPage::push();
}
void objc_autoreleasePoolPop(void *ctxt) {
AutoreleasePoolPage::pop(ctxt);
}
内部实际上是对 AutoreleasePoolPage 的调用
objc_autoreleasePoolPush
每当自动释放池调用 objc_autoreleasePoolPush 时,都会把边界对象放进栈顶,然后返回边界对象,用于释放。
AutoreleasePoolPage::push(); 调用👇
static inline void *push() {
return autoreleaseFast(POOL_BOUNDARY);
}
autoreleaseFast👇
static inline id *autoreleaseFast(id obj)
{
AutoreleasePoolPage *page = hotPage();
if (page && !page->full()) {
return page->add(obj);
} else if (page) {
return autoreleaseFullPage(obj, page);
} else {
return autoreleaseNoPage(obj);
}
}
👆上述方法分三种情况选择不同的代码执行:
- 有 hotPage 并且当前 page 不满,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中
- 有 hotPage 并且当前 page 已满,调用 autoreleaseFullPage 初始化一个新的页,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中
- 无 hotPage,调用 autoreleaseNoPage 创建一个 hotPage,调用 page->add(obj) 方法将对象添加至 AutoreleasePoolPage 的栈中
最后的都会调用 page->add(obj) 将对象添加到自动释放池中。 hotPage 可以理解为当前正在使用的 AutoreleasePoolPage。
AutoreleasePoolPage
是以栈的形式存在,并且内部对象通过进栈、出栈对应着 objc_autoreleasePoolPush 和 objc_autoreleasePoolPop
当我们对一个对象发送一条 autorelease 消息时,实际上是将这个对象地址加入到 autoreleasePoolPage 的栈顶 next 指针的指向的位置
Runloop 与 Autorelease
iOS 在主线程注册了两个 observer
__第一个observer __
监听了 kCFRunloopEntry, 会调用 objc_autoreleasePool_push()
第二个 observer
监听了 kCFRunloopBeforeWaiting 会调用 objc_autoreleasePool_pop() 、objc_autoreleasePool_push()
监听了 kCFRunloopExit 事件,会调用 objc_autoreleasePool_pop()