Objective-C RunTime 学习笔记 之 AutoReleasPool

1、结构

struct magic_t {
    /* 魔法 */
    static const uint32_t M0 = 0xA1A1A1A1;
#   define M1 "AUTORELEASE!"
    static const size_t M1_len = 12;
    uint32_t m[4];
    /* 省略各种方法 */
#   undef M1
};

/* AutotRelease 重要:重载了new和delete运算符号,使每个Page对象固定大小 */
class AutoreleasePoolPage 
{
#define POOL_SENTINEL nil
    static pthread_key_t const key = AUTORELEASE_POOL_KEY; /* TSD __PTK_FRAMEWORK_OBJC_KEY3 */
    static uint8_t const SCRIBBLE = 0xA3;  // 0xA3A3A3A3 after releasing
    static size_t const SIZE = 
#if PROTECT_AUTORELEASEPOOL
        PAGE_MAX_SIZE;  // must be multiple of vm page size
#else
        PAGE_MAX_SIZE;  // size and alignment, power of 2 (CGS. 4096 < bytes per 80386 page >)
#endif
    static size_t const COUNT = SIZE / sizeof(id);
    magic_t const magic;
    id *next;   /* objc 对象列表指向下一个未使用的区域 */
    pthread_t const thread; /* page对应线程 */
    /* 链表结构 */
    AutoreleasePoolPage * const parent; /* 父 */
    AutoreleasePoolPage *child;         /* 子 */
    uint32_t const depth;               /* 链表深度 */
    uint32_t hiwat;
    // SIZE-sizeof(*this) bytes of contents follow
    //省略各种方法
    //00000哨兵分割线
    //各种objc对象,
}

2、 每个线程对应一个AutoReleasePoolPage 的对象列表

2.1) 线程销毁的时候,释放AutoReleasePoolPage 以及所有对象

2.2) AutoReleasePoolPage 为C++对象,由于重载了new 和 delete 运算符,确保每一个Page分配固定大小(貌似4K)。在类的实例变量/方法列表后存储Foundation对象。而类的next 成员变量则指向下一个Foundation对象。AutoReleasePoolPage 有判断是否为空和满的成员函数,以此来判断当前线程是否新创建一个AutoReleasePool对象。没创建一个对象,都会设置parent、chilid属性,构成双向链表,而hotPage则是存储在线程的本地存储中。系统初始化时会给线程初始化钩子函数  int r __unused = pthread_key_init_np(AutoreleasePoolPage::key,  AutoreleasePoolPage::tls_dealloc); 确保在线程销毁的时候,释放AutoReleasePool, 由于hotPage存存在TLS中,并且page为双向链表,可以通过hotPage遍历整个Page俩表,确保释放Page对象。

      每个oc对象发送 autorelease 消息或者使用__autorelease 修饰的时候,从当前线程取出hotPage(), 整个函数从线程本地存储中取,如果没有AutoReleasePoolPage链表则创建一个,否则取出AutoReleasePoolPage,查看是否full,如果full则创建一个新的AutoReleasePoolPage,设置parent 和 child属性, 然后设置为hotPage(存入线程中本地存储中 TLS)。

  @autoreleasepool {

    //some code

  }

所有使用 @autoreleasepool block起来的代码,都会在形成

  void *pool = AutoReleasePoolPage::push();

  //some code

  AutoReleasePoolPage::pop(pool);

3、 主线程AutoReleasePoolPage何时pop?

文档中说每个 event loop(鼠标事件、点击事件等)都会在事件的will 时 pool->push(),did时 pool->pop(void *).。OS 会在主线程的RunLoop循环注册一些列观察者,在进入时调用 void *pool = AutoReleasePoolPage::push(); ,退出时调用 AutoReleasePoolPage::pop(pool); 这样子确保每一次循环都进行pool的释放。


posted @ 2018-03-23 15:37  茄菲兔  阅读(331)  评论(0编辑  收藏  举报