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的释放。

												

Objective-C RunTime 学习笔记 之 AutoReleasPool的更多相关文章

  1. 我的runtime学习笔记

    0.简介: OC方法不同于C语言函数,属于动态调用过程,在编译的时候并不能决定真正调用哪个函数,只有在真正运行的时候才会根据函数的名称找到对应的函数来调用. 至于其他理论上的东西不必讲太多,编程讲的就 ...

  2. runtime学习笔记

    获取属性objc_property_t * propertys = class_copyPropertyList(clazz, &outCount); 获取属性名NSString * key ...

  3. iOS Runtime学习笔记

    Associated Objects: @interface NSObject (AssociatedObject) @property (nonatomic, strong) id associat ...

  4. Objective-C学习笔记---构造函数和析构函数

    简单的讲,构造函数就是在创建一个对象的时候起到初始化的作用,对这个对象里的一些成员变量进行初始化,析构函数就是在对象被删除进行一些清理工作,也就是专门的扫尾工作,下面用代码来进行具体说明. 一.构造函 ...

  5. Objective-C RunTime 学习笔记 之 消息转发流程

    1) 当向某个对象发送消息时,先从cache(cache_t)中查找方法对象(method_t),如果找到则进行回调:否则通过查找对象的类(元类)定义中方法列表,一直追溯到NSObject, 如果找到 ...

  6. Objective-C RunTime 学习笔记 之 atomic/nonatomic 关键字

    atomic修饰的是变量/方法,对于可变对象的指针变量是安全的,内部实现加了锁,但是对可变对象本身没什么影响,不安全还是不安全.另外atomic仅仅对编译器生产的getter.setter有效,如果自 ...

  7. Objective-C RunTime 学习笔记 之 基础结构体

    1.OC 运行期常用对象结构体 基本的结构体定义 typedef objc_class Class; /* 类 */ typedef objc_object *id; /* 各种类型,只要第一个字段为 ...

  8. Flink学习笔记:Flink Runtime

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  9. objc_msgSend消息传递学习笔记 – 消息转发

    该文是 objc_msgSend消息传递学习笔记 – 对象方法消息传递流程 的基础上继续探究源码,请先阅读上文. 消息转发机制(message forwarding) Objective-C 在调用对 ...

随机推荐

  1. PHP正则提取或替换img标记属性

    <?php   /*PHP正则提取图片img标记中的任意属性*/ $str = '<center><img src="/uploads/images/20100516 ...

  2. Ubuntu下安装sbt

    参考  ubuntu14 手动安装sbt 1.下载sbt通用平台压缩包:sbt-0.13.5.tgz http://www.scala-sbt.org/download.html 2.建立目录,解压文 ...

  3. MySQL 数据热备份

    mysqlhotcopy使用lock tables.flush tables和cp或scp来快速备份数据库.它是备份数据库或单个表最快的途径,完全属于物理备份,但只能运行在数据库目录所在的机器上. 与 ...

  4. Cocoapods 创建自己的公开库、私有库

    如何创建自己的共有库 1.注册Trunk trunk需要CocoaPods 0.33版本以上,用pod --version 命令查看版本 CocoaPods版本 如果版本低,需要升级: sudo ge ...

  5. layui---表单验证

    使用layui,使用它的表单验证也是比不可少的,下面就来总结下: <!-- 不用form 用div也可以 --> <form class="layui-form" ...

  6. 案例源码解读及思路:RabbitMQ在springboot中的配置

    程序员的高级之处不是什么都会,而是对自己不会的进行抽象,然后完成自己的工作.比如对于RabbitMQ,按照字面理解,就将其看成Message Queue,也就是用来容纳对象的集合.很多功能都拆分给一个 ...

  7. java基础编程

    java的类和常用编程模式还是要多练习,多手写java代码 return new String(filecontent, encoding); 看懂这个意思了吗?第一次见这个构造函数吧,而String ...

  8. poj1696

    没看题解,搜了一下都是什么叉积凸包,根本没有必要用吧.. 显然这个题我们找夹角就可以了,根据高中的公式 a·b=|a|*|b|*cos<a,b> 所以用点积找一个 cos<a,b&g ...

  9. linux的基本操作(mysql 的基本操作)

    Mysql 的基本操作 在前面两个章节中已经介绍过MySQL的安装了,但是光会安装还不够,还需要会一些基本的相关操作.当然了,关于MySQL的内容也是非常多的,只不过对于linux系统管理员来讲,一些 ...

  10. 写jquery插件(转载)

    如今做web开发,jquery 几乎是必不可少的,就连vs神器在2010版本开始将Jquery 及ui 内置web项目里了.至于使用jquery好处这里就不再赘述了,用过的都知道.今天我们来讨论下jq ...