zend_mm_remove_from_free_list
2015-09-15 16:59:47 5 举报
`zend_mm_remove_from_free_list`是一个在Zend引擎中定义的函数,主要用于处理PHP中的内存管理。这个函数的主要作用是从自由列表(free list)中移除一个已经分配但不再使用的内存块。当PHP脚本执行完毕后,所有动态分配的内存都需要被正确地释放以回收资源。这个函数就是在这个过程中发挥作用,它通过将已分配的内存块从自由列表中移除,确保这些内存块可以被后续的内存分配操作重用,从而提高内存的使用效率。同时,这也有助于防止因内存泄露而导致的程序运行效率下降或者崩溃。
作者其他创作
大纲/内容
subst_block:走到这个分支中,两种可能性:1)mm_block是large_free_buckets[]中的树中blk,是它所在层的唯一blk,没有prev和next,但是至少有一个孩子,此时prev指向它的后裔(即最小的比它大的block)2)mm_block是large_free_buckets[]中的树中blk,不是它所在层的唯一blk,不一定有孩子,此时prev指向它的后裔(即和它同大小的同层blk)
因为mm_block没有链接其它元素,那么它肯定属于large_free_buckets[]里面的某个树表,它有可能是一个叶子blk,也有可能是树中某一层唯一的树中blk,无论哪种情况,它一定有parent和child指针,但都可能为NULL
否
不正常
else if (UNEXPECTED(mm_block-parent == ZEND_MM_REST_BLOCK))mm_block是属于rest_buckets吗?
prev链接着其它blk
因为mm_block链接着其它元素,说明mm_block的情况有三种可能性:1)它属于free_bucket[]的某个链表里面2)它是large_free_buckets[]某个树表里面某一层,在同一层有与它同大小的blk,它肯定有parent和child指针,但都可能为NULL3)它属于rest_buckets[]
if (EXPECTED(prev == mm_block))校验mm_block的prev是否链接着其它blk还是链接着它自己?
完成任务,现在的mm_block已经完全与它原来所在的heap中某个数据结构脱离了关系,我们可以直接使用了注意:我们没有费力去清除mm_block本身的各个指针,因为它在被返回给用户使用前,会被从mm_free_block结构转为mm_block结构,其指针部分的内存将被debug_info等结构覆盖,如果debug_info覆盖后仍剩余,则直接给用户使用了。
走到这个分支,两种可能性:1)mm_block右孩子为空,prev指向左孩子,左孩子不为空2)mm_block右孩子不为空,prev指向右孩子,自然不为空这两种情况,mm_block都是一个树中block
prev-next_free_block = next;next-prev_free_block = prev;将mm_block在链表中的前后blk链接起来这一步使得mm_block脱离了它原来所在的链表(无论是free_buckets还是rest_buckets还是large_free_buckets)
有
if (UNEXPECTED(prev-next_free_block != mm_block) || UNEXPECTED(next-prev_free_block != mm_block))校验mm_block在某个链表中链接情况是否正常
prev链接着其它自己
zend_mm_panic(\"zend_mm_heap corrupted\");
自己想到的解答:heap-large_free_buckets[index]指向的树,与普通的二叉树不同。普通的二叉树,要保证任意一个节点的左孩子里面的值要小于等于该节点,而其右孩子里面的值要大于等于该节点。但是heap-large_free_buckets[index]里面的树不需要这个特性。它的特性是:1)任意节点的左右孩子里面的值都一定不等于该节点的值,至于大于还是小于,与位于左孩子或右孩子无关。2)任意节点的左孩子里面的值一定小于右孩子里面的值。所以,我们在删除一个树中节点的时候,不需要遵从二叉树节点删除的规则,而是直接选择左右孩子中任意一个叶子节点即可,PHP源码里的实现只是达到这个目的的一种方法罢了,没有其他特殊含义。
没有
if (EXPECTED(prev == NULL))这个孩子为空吗?
while (*(cp = &(prev-child[prev-child[1] != NULL])) != NULL) {prev = *cp; rp = cp;}依照一定原则,循环地去找mm_block的孩子里面最下层的一个叶子block原则是:如果当前block的右孩子不为空,就走右孩子,如果为空就走左孩子直到当前block的两个孩子都为空,就停止,停止时,prev指向最后这个两个孩子都为空的叶子block,rp指向它的parent
为空
k
*rp = NULL;将prev与它parent脱离
因为mm_block是一个small free block,属于free_buckets某个链表中。而在free_buckets的任意链表中,只有当mm_block是该链表唯一block时,它的prev和next才会相同,且都指向free_buckets[index]
heap-rest_count--;因为已经将mm_block的前后链接无需再多操作,减去rest_buckets里面的计数即可
按照二叉树删除时,保存树的正确性的原则,一个树中节点的后裔应该是整个树中所有比它大的节点中的最小的那个,这个原则应用在large_free_buckets[]中,难点我们不应该是在被删除节点(mm_block)的右孩子里面找到最左的叶子,或者如果它没有右孩子,我们应该向上寻找,直到遇到第一个这样的父节点吗?:被删除节点属于它的左孩子而不是右孩子
size_t index = ZEND_MM_BUCKET_INDEX(ZEND_MM_FREE_BLOCK_SIZE(mm_block));if (EXPECTED(heap-free_buckets[index*2] == heap-free_buckets[index*2+1])) {heap-free_bitmap &= ~(ZEND_MM_LONG_CONST(1) free_bitmap,记录这个index不再有free block可用
是
zend_mm_free_block *prev = mm_block-prev_free_block;zend_mm_free_block *next = mm_block-next_free_block;能进入到这个函数中的mm_block,一定属于heap的free_bucket[]或者large_free_buckets[]中,也只有这两个链表里面的block在被使用前需要从链表中脱离无论是在这两个链表中的哪一个里面,mm_block都应该存有prev、next两个指针但不一定会有parent和child
不为空
走到这里,说明mm_block是free_buckets里面某个链表中的非唯一blk,既然在前面我们已将它与所在链表脱离,这里无需其他操作了
if (EXPECTED(prev == next))mm_block的prev和next是否指向同一个地方?
rp = &mm_block-child[mm_block-child[1] != NULL];prev = *rp;让prev指向mm_block的一个孩子,如果右孩子不为空就指右孩子,如果右孩子为空就指左孩子
无论上述两种可能性的哪一种,我们在这里都需要做一件事:将mm_block替换成它在树表中的后裔,来保证树的正确性。具体的方法就是将mm_block的parent、child全都赋给prev指向的blk(mm_block的后裔),and vice versa,这些操作无所谓mm_block和prev目前是否有任何孩子:ZEND_MM_CHECK_TREE(mm_block);*mm_block-parent = prev;prev-parent = mm_block-parent;if ((prev-child[0] = mm_block-child[0])) {ZEND_MM_CHECK_TREE(prev-child[0]);prev-child[0]-parent = &prev-child[0];}将mm_block左孩子赋给prev,如果左孩子不为NULL,将左孩子parent设为previf ((prev-child[1] = mm_block-child[1])) {ZEND_MM_CHECK_TREE(prev-child[1]);prev-child[1]-parent = &prev-child[1];}将mm_block右孩子赋给prev,如果右孩子不为NULL,将右孩子parent设为prev
if (UNEXPECTED(next != mm_block))校验mm_block的next是否也链接着自己
else if (UNEXPECTED(mm_block-parent != NULL))走到这里,说明mm_block肯定是在large_free_buckets里面的blk,那么它有parent吗?
走到这个分支,只有一个可能性:mm_block右孩子为空,prev指向左孩子,又为空,那么mm_block是一个叶子block
if (EXPECTED(ZEND_MM_SMALL_SIZE(ZEND_MM_FREE_BLOCK_SIZE(mm_block))))mm_block是一个small free block吗?
zend_mm_panic(\"zend_mm_heap corrupted\");走到这个分支中,无论属于上面说的两种情况的哪一个,mm_block的prev和next都应该指着自己,如果不是,就说明zend_mm_heap corrupted
走到这里,说明mm_block是large_free_buckets[]里面某个树表的某一层的非唯一blk,它原本和同样大小的其它blk链接在一起,但因为它没有parent,所以它一定不是这一层得这个链表的表头blk。因为我们在上面已经将它与它原来所在的链表脱离,所以我们在这里无需任何操作了
走到这里,说明mm_block是large_free_buckets[]里面某个树表的某一层的非唯一blk,它原本和同样大小的其它blk链接在一起,但因为它有parent,所以它是这一层得这个链表的表头blk,虽然我们在上面已经将它与它原来所在的链表脱离,我们依然要将这个mm_block替换成它自己在树表中的后裔(即和它同大小的同层blk)
0 条评论
下一页