Autorelease Pool

前言

之前有写过一篇关于AutoreleasePool的理解的总结,总觉的不够深入,所以重起一篇。本篇从阅读官方文档和autorelasepool的源码入手来记录。

Autorelease Pool

什么是autorelease pool

 从官方文档中的解释,autorelease pool存储着一些对象,当pool销毁或者耗尽时会向池中全部对象发送release消息。

autorelease pool的创建和池内对象的释放时机

应用程序在每次事件循环(event loop)的开始,自动在主线程上创建一个自动释放池,并在每次事件循环(event loop)结束时向池内对象发送release消息进行释放。手动创建的autorelease pool中的对象在block外被释放掉。

autorelease pool 与 thread

当你通过NSThread另外开辟的子线程时,你需要自己创建一个autorelease pool。子线程默认是没有自动释放池的。但是使用GCD开辟的线程会自动创建pool。

autorelease pool的结构

我们都知道在iOS开发中,main函数作为程序的入口,包含了一个@autoreleasepool,我们通过clang重新编译一下会发现main函数的实现变成了下图的样子

@autoreleasepool被转成了一个__AtAutoreleasePool。__AtAutoreleasePool是一个结构体

结构体的构造函数中会调用objc_autoreleasePoolPush(),析构函数中会调用objc_autoreleasePoolPop(void *)

这俩个方法可以再NSObject.mm的源码中找到实现。 

方法实现中出现了一个新的类AutoreleasePoolPage,提取出来的大致定义是这样的

magic 用来校验 AutoreleasePoolPage 的结构是否完整;

next 指向最新添加的 autoreleased 对象的下一个位置,初始化时指向 begin() ;

thread 指向当前线程;

parent 指向父结点,第一个结点的 parent 值为 nil ;

child 指向子结点,最后一个结点的 child 值为 nil ;

depth 代表深度,从 0 开始,往后递增 1;

hiwat 代表 high water mark 

当next指向begin时代表该page为空,当next指向end时代表page已满。

autorelease pool就是由这些page组成的双向链表结构且每一个page的可用空间是固定的4096个字节

Autorelease Pool方法调用顺序

objc_autoreleasePoolPush

上面说了_AtAutoreleasePool在初始化的时候会调用objc_autoreleasePoolPush,我们来看下这个方法的实现,整理后差不多是这样

调用autoreleaseFast并传入POOL_BOUNDARY,这里POOL_BOUNDARY作为哨兵后面会说。

 autoreleaseFast (hotPage:当前正在使用的page)

大体的逻辑是这样

  1. 通过hotPage()方法获取hotPage
  2. 当hotPage存在并且空间未满时将传入的obj添加到page中
  3. 如果hotPage满了,就另外新建一个page并将obj添加到里面
  4. 如果hotPage不存在,就创建一个hotPage并将obj添加到里面

hotPage 

通过tls(Thread Local Storage)获取hotPage

page->add() 

autoreleaseFullPage

autoreleaseNoPage

创建一个parent为nil的page并添加一个哨兵

未完待续

猜你喜欢

转载自www.cnblogs.com/kaisi/p/10119095.html