AutoreleasePool

AutoReleasePool

AutoreleasePool的实现原理

@autoreleasePool = __AtAutoreleasePool __autoreleasePoolc++

__AtAutoreleasePool 结构体
复制代码

AutoreleasePool 是 oc 的一种内存回收机制,正常状况下变量在超出做用域的时候 release,可是若是将变量加入到 pool 中,那么release 将延迟执行objective-c

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 *)markdown

具体实现以下:oop

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

void objc_autoreleasePoolPop(void *ctxt) {
    AutoreleasePoolPage::pop(ctxt);
}
复制代码

内部其实是对 AutoreleasePoolPage 的调用ui

objc_autoreleasePoolPush

每当自动释放池调用 objc_autoreleasePoolPush 时,都会把边界对象放进栈顶,而后返回边界对象,用于释放。spa

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);
   }
}
复制代码

👆上述方法分三种状况选择不一样的代码执行:code

- 有 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 在主线程注册了两个 observerorm

__第一个observer __

监听了 kCFRunloopEntry, 会调用 objc_autoreleasePool_push()

第二个 observer

监听了 kCFRunloopBeforeWaiting 会调用 objc_autoreleasePool_pop() 、objc_autoreleasePool_push()

监听了 kCFRunloopExit 事件,会调用 objc_autoreleasePool_pop()