自动释放池

2019-10-11  本文已影响0人  Harely

自动释放池的创建和释放,销毁的时机如下所示


Autorelease原理

AutoreleasePoolPage
ARC下,使用@autoreleasepool{}来使用一个AutoreleasePool,随后编译器将其改写成下面的样子:

void *context = objc_autoreleasePoolPush();
{// {}中的代码

}
objc_autoreleasePoolPop(context);

  而这两个函数都是对AutoreleasePoolPage的简单封装,所以自动释放机制的核心就在于这个类。
AutoreleasePoolPage是一个C++实现的类

image.png

  若当前线程中只有一个AutoreleasePoolPage对象,并记录了很多autorelease对象地址时内存如下图:


AutoreleasePoolPage 存储对象

  图中的情况,这一页再加入一个autorelease对象就要满了(也就是next指针马上指向栈顶),这时就要执行上面说的操作,建立下一页page对象,与这一页链表连接完成后,新page的next指针被初始化在栈底(begin的位置),然后继续向栈顶添加新对象。

  所以,向一个对象发送- autorelease消息,就是将这个对象加入到当前AutoreleasePoolPage的栈顶next指针指向的位置。

Autorelease 释放时刻

  每当进行一次objc_autoreleasePoolPush调用时,runtime向当前的AutoreleasePoolPage中add进一个哨兵对象,值为0(也就是个nil), 如下图:

push 哨兵对象

objc_autoreleasePoolPush 的返回值是这个哨兵对象的地址,被objc_autoreleasePoolPop (哨兵对象)作为入参,于是根据传入的哨兵对象地址找到哨兵对象所处的page。
  在当前page中,将晚于哨兵对象插入的所有autorelease对象都发送一次- release消息,并向回移动next指针到正确位置

  补充2:从最新加入的对象一直向前清理,可以向前跨越若干个page,直到哨兵所在的page。objc_autoreleasePoolPop执行后,最终变成了下面的样子:

pop 哨兵对象

嵌套的AutoreleasePool
  知道了上面的原理,嵌套的AutoreleasePool就非常简单了,pop的时候总会释放到上次push的位置为止,多层的pool就是多个哨兵对象而已,就像剥洋葱一样,每次一层,互不影响。

上一篇 下一篇

猜你喜欢

热点阅读