autorelease对象释放时机?
在当前runloop循环结束的时候,runloop会执行objc_autoreleasePoolPop(context),这个操作才是真正释放autorelease对象的操作(具体实现后面会讲到)。或者是手动的@autoreleasepool{}结束之后,因为编译器会在@autoreleasepool{}的开始跟结束自动加上push跟pop。
12345struct __AtAutoreleasePool {__AtAutoreleasePool() {atautoreleasepoolobj = objc_autoreleasePoolPush();}~__AtAutoreleasePool() {objc_autoreleasePoolPop(atautoreleasepoolobj);}void * atautoreleasepoolobj;};autorelease原理
autoreleasePool本身是一个双向链表,保存的元素是autoreleasePoolPage对象。
(通过其中的parent跟child就能看出整个autoreleasePool是个双向链表)
每个autorelease对象会push到poolpage中,next指针指向的是栈顶位置也就是下一个可以存放autorelease对象的位置:
当调用 [obj autorelease]时,就会把对象放入next的位置。当page满了之后,会开辟一个新的page。
每次调用objc_autoreleasePoolPush时,会插入一个哨兵对象(POOL_SENTINEL)到栈顶:
哨兵对象其实就是一个nil
当释放autoreleasepool时(即调用objc_autoreleasePoolPop(哨兵对象)),则会依次调用哨兵对象后面对象的release方法,从而实现对象的释放。释放结束之后page就变成:
系统如何实现在runloop一次迭代结束时执行objc_autoreleasePoolPop释放autoreleasePool的?
主runloop启动时,系统会add两个observer,分别监听runloop的启动状态(kCFRunLoopEntry)跟即将休眠和退出态(kCFRunLoopBeforeWaiting | kCFRunLoopExit)。在启动的observer回调中执行objc_autoreleasePoolPush操作,在休眠或退出时执行objc_autoreleasePoolPop。
因为主runloop是在主线程中,那子线程的autorelease对象怎么办?
autoreleasePoolPage内部有一个thread变量来表明当前page所在对象,并且在工作线程中打印当前runloop会发现当前runloop并没有类似的observer来监听runloop的状态,所以可以猜测:
所有线程的autoreleasePoolPage都保存在一个双向链表中,所有线程的autorelease对象都会保存在这个链表中对应线程的page中,这个双向链表由主runloop统一管理(只是一个猜测,没有找到相关的介绍,所以如果哪位了解这块的话跪求讲解)
参考: