自动释放池

  • AutoReleasePool的实现原理?
  • AutoReleasePool为什么可以嵌套调用?

自动释放池

  • 是以栈为节点通过双向链表的形式结合而成的
  • 是和线程一一对应的

通过clang编译器查看@autoreleasepool{}

{
__AtAutoreleasePool __autoreleasepool;
...
}

__AtAutoreleasePool 又是什么?查看编译后的结构

struct __AtAutoreleasePool {
//// 构造函数,在创建结构体的时候调用
  __AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}
//// 析构函数,在结构体销毁的时候调用
  ~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}
  void * atautoreleasepoolobj;
};

__AtAutoreleasePool是一个结构体,所以创建时会调用其构造函数__AtAutoreleasePool(),当离开其作用域后,会调用其析构函数~__AtAutoreleasePool()

查看objc源码得到objc_autoreleasePoolPush和objc_autoreleasePoolPop的实现

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

即相当于

objc_autoreleasePoolPush(void)
....{}中的代码
objc_autoreleasePoolPop(void *ctxt)

那么其实可以看出自动释放池是由AutoreleasePoolPage实现的
通过objc源码查看其数据结构,它是一个c++的class

class AutoreleasePoolPage {
....
    magic_t const magic; //用来校验 AutoreleasePoolPage 的结构是否完整
    id *next;//指向最新添加的 autoreleased 对象的下一个位置,初始化时指向 begin()
    pthread_t const thread;//指向当前线程
    AutoreleasePoolPage * const parent;//指向父结点,第一个结点的 parent 值为 nil
    AutoreleasePoolPage *child;//指向子结点,最后一个结点的 child 值为 nil
    uint32_t const depth;//代表深度,从 0 开始,往后递增 1
    uint32_t hiwat;//代表 high water mark
...
}

每个AutoreleasePoolPage对象占用4096字节内存,除了用来存放它内部的成员变量,剩下的空间用来存放autorelease对象的地址
所有的AutoreleasePoolPage对象通过双向链表的形式连接在一起

一次pop相当于一次批量的pop操作

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容