php 内存池,浅谈PHP源码三十二:PHP内存池中的emalloc/efree层与堆(heap)层

本文详细解析了PHP内存管理中的emalloc和efree函数,以及它们与堆内存层的交互。emalloc通过搜索不同大小的内存块列表来分配内存,而efree则负责释放内存并进行堆的整理。文章还探讨了内存块的合并与内存段的管理策略,对于理解PHP内存机制具有重要意义。
摘要由CSDN通过智能技术生成

这篇文章主要介绍了关于浅谈PHP源码三十二:PHP内存池中的emalloc/efree层与堆(heap)层,有着一定的参考价值,现在分享给大家,有需要的朋友可以参考一下

浅谈PHP源码三十二:PHP内存池中的emalloc/efree层与堆(heap)层

emalloc/efree层是整个内存体系中最上层结构,它通过与堆层的交换使用PHP自带的内存管理机制。如果有设置USE_ZEND_ALLOC为0,则直接使用malloc/free等函数直接操作内存。

这里将从emalloc与efree两个函数的实现解析emalloc/efree层与堆层的交互,及堆层对于内存的管理机制。

【emalloc】

emalloc函数是从zend_alloc.h 70行开始。

emalloc是一个宏,其对应了_emalloc函数。

在_emalloc函数中,如果未使用zend的内存管理机制,则直接调用malloc函数,否则调用_zend_mm_alloc_int

[emalloc() -> _emalloc() -> _zend_mm_alloc_int() ]

在_zend_mm_alloc_int函数中,程序会处理真实需要的内存小于或大于等于ZEND_MM_MAX_SMALL_SIZE(272)两种情况,如果小于ZEND_MM_MAX_SMALL_SIZE,则会搜索free_buckets,看是否有合适的内存块,如果可以在free_buckets中找到合适的块使用,同直接跳转到zend_mm_finished_searching_for_block,否则执行zend_mm_search_large_block()

[emalloc() -> _emalloc() -> _zend_mm_alloc_int() -> zend_mm_search_large_block()]

zend_mm_search_large_block函数用来在large_free_buckets中查找合适的内存块。其中当对于ZEND_MM_LARGE_BUCKET_INDEX(true_size)大小的没有找到时,需要查找更大块列表中的最小块。

如果在大块列表和小块列表中都没有,则需要从剩余列表块中查找,如果找到,则同样跳转到zend_mm_finished_searching_for_block

如果三个列表中都没有找到,则需要重新增加内存分配。此时调用storage层的分配函数进行分配,其中内存的大小,如果需要分配的内存大于block_size,则需要根据大小重新计算,否则直接分配block_size大小的内存。

分配内存完后,需要重新整理堆,此时需要重新计算堆中的内存大小,将新分配的内存添加到segments_list的前面。

如果在上面的操作中是直接跳转到zend_mm_finished_searching_for_block,则需要将使用了的内存块从对应的列表中移除(此处应该是一个标记的过程,伪移除)

接下来,根据剩下的内存大小,将其移到空闲列表或剩余列表。

最后返回分配的块。

在emalloc整个过程中,有以下一些注意点。

ZEND_MM_BUCKET_INDEX(true_size)定位在bucket中的位置,这个值大于等于0,小于32。

其实现如下:#define ZEND_MM_BUCKET_INDEX(true_size) ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))

free_bitmap和large_free_bitmap的值都是0到31。

【efree】

efree函数是从zend_alloc.h 72行开始。

efree是一个宏,其对应了_efree函数。

在_efree函数中,如果未使用zend的内存管理机制,则直接调用free函数,否则调用_zend_mm_free_int

[efree() -> _efree() -> _zend_mm_free_int() ]

堆首先将整个堆的大小减少,如果当前块的后一个块是空闲块,则将后一个空闲块从空闲块列表中删除并与当前块合并,如果当前块的前一个块是空闲块,则将前一个空闲块从空闲块列表中删除并与当前块合并,指针指向前一个空闲块。如果此时当前块是开始的块,则调用zend_mm_del_segment将整段内存清除,如果不是开始块,则将合并后的块添加到空闲块列表。

以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!

相关推荐:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值