最近在拜读Draveness大佬的一篇文章自动释放池的前世今生 —- 深入解析 autoreleasepool,看到文中给读者留了一个问题:
我到现在也不是很清楚为什么要根据当前页的不同状态 kill 掉不同 child 的页面。
关于AutoreleasePool
是什么,强力推荐阅读原文,写的很好。这里就不说了,直接讨论问题。
首先是整个pop
方法的实现:
1 | static inline void pop(void *token) |
我们先看看释放的函数releaseUntil
,它在释放的时候其实会一直顺着parent
往前释放,直到参数stop
,也就是说可能一次性释放好几个page
。
1 | // 代码有所删减 |
然后我们来看看这段有疑问的代码
1 | // memory: delete empty children |
这块代码的作用是删除空的子节点,释放内存。pop之后三种情况:
- 当前
page
为空,直接kill掉当前page
,然后把parent
设置为hotpage
; - 当前
page
为空,而且没有parent
,kill掉当前page
,hotpage
置为空; - 当前
page
不为空,但是有child
,如果当前page
的空间占用不到一半,释放child
,如果当前page
的空间占用超过一半,且child
还有child
,直接释放这个孙子辈的page
。(对于第三步注释中的解释是:keep one empty child if page is more than half fully)
我们再看看kill
的实现,可以发现他是会顺着child
一直往后释放,保证释放节点的child page
都被释放了。
1 | void kill() |
到这里就可以得出结论了:
- pop之后,所有
child page
肯定都为空了,且当前page
一定是hotPage
- 系统为了节约内存,判断,如果当前
page
空间使用少于一半,就释放掉所有的child page
,如果当前page
空间使用大于一半,就从孙子page
开始释放,预留一个child page
。