iOS | autoreleasePool的实现
-
每一个线程的autorelease就是一个指针的堆栈。
-
每一个指针代表一个要release的对象或者是POOL_SENTINEL(哨兵对象,代表一个autorelease的边界,释放一个autorelease pool需要将哨兵对象后的所有release节点对象释放)。
-
每一个pool token代表的就是这个pool所对应的POOL_SENTINEL的结点的内存位置,当这个pool被pop后,这个token后的所有的结点对应的对象内存都会被释放。
-
autoreleasePool的实现是通过AutoreleasePage结点实现的()
-
这个堆栈被划分成了一个以page为结点的双向链表。pages会在必要的时候动态增加或者删除
-
Thread_local storage(线程局部存储)指向hot page,即最新添加的autoreleased对象所在的那个page。
AutoreleasePoolPage内存结构如下所示:
-
magic 用来校验 AutoreleasePoolPage 的结构是否完整;
-
next 指向最新添加的 autoreleased 对象的下一个位置,初始化时指向 begin() ;
-
thread 指向当前线程;
-
parent 指向父结点,第一个结点的 parent 值为 nil ;
-
child 指向子结点,最后一个结点的 child 值为 nil ;
-
depth 代表深度,从 0 开始,往后递增 1;
-
hiwat 代表 high water mark 。
-
当 next == begin() 时,表示 AutoreleasePoolPage 为空;当 next == end() 时,表示 AutoreleasePoolPage 已满。此时再创建一个AutoreleasePoolPage结点。
pool通过 push 和 pop 操作来添加autoreleasepool和移除autoreleasepool:
- push操作实际就是前next指针添加一个哨兵,然后再往哨兵的next后添加这个pool要release的对象。
- pop操作会将内存地址在 pool token 之后的所有 autoreleased 对象都会被 release 。直到 pool token 所在 page 的 next 指向 pool token 为止。
此时,如果执行 pop(token1) 操作,那么该 autoreleasepool 堆栈的内存结构将会变成如下图所示: