PHP内存管理ZMM(五)-大内存区large_free_bucket的存入
2230 字 - 5 分钟之前的章节中介绍过large_free_bucket的存入条件。这一篇将介绍large_free_bucket的主要结构包括其中的链表结构和树结构和存入取出流程。本章讲通过图示大内存区域内存分部情况。
什么时候会向large_free_bucket存入内存块
这里在复习下存入large_free_bucket流程。在调用emalloc申请能存,且在当前heap中没有找到合适内存块,emalloc函数会调用malloc向内核申请内存。向内核申请每次只能申请 heap->block_size倍数大小内存。所以内核申请到的 heap->block_size倍数 大小的内存并不会全部返回到emalloc调用者,而是有剩余。
举个例子,假设heap->block_size=256k,如果emalloc调用者申请大小为250k时,emalloc内部会向内核申请256k大小的内存。所以会有6k的内存剩余,这6k的内存将会存入到大内存区large_free_bucket。
另外一个例子,假设heap->block_size=256k,如果emalloc调用者申请大小为260k(大于256k)时,emalloc会申请256*2=512k大小的内存,此时会有512k-260k=252k的内存剩余。此时剩下的252k内存会存入到剩余内存区rest_bucket。
手动构建large_free_bucket结构
large_free_bucket结构举例
现在假设有以下内存块在large_free_bucket,分别为:
|
|
上面第一列中是准备存入heap中的内存大小,第二列为其二进制。第三列为_zend_mm_alloc_int传入的内存大小。
之前提过用gdb手动调用_zend_mm_alloc_int的方法,详情看一下前面的文章“PHP内存管理ZMM(四)-GDB调试php源码并手动调用ZMM相关函数”。
存入第一个大小为600b的内存
手动调用
|
|
申请大小261496b(第一行最后一行的数值),ZMM会向内核申请262144(256k)的内存,去掉部分结构体占用的内存48b。则剩余600b大小的内存,这600b的内存讲放入大内存区域中。
用gdb查看heap->large_free_buckets当前的情况
|
|
图示如下:
如图所示,插入的第一个元素zend_mm_free_block[600](用zend_mm_free_block[600]表示大小为600的zend_mm_free_block内存结构),其prev_free_block和next_free_block均指向其本身,其parent为&heap->large_free_buckets[9],heap->large_free_buckets[9]则指向zend_mm_free_block[600]。
相关代码:引自
存入大小为600b的内存
手动调用
|
|
用gdb查看heap->large_free_buckets当前的情况
|
|
图示如下:
这里要注意的地方是zend_mm_free_block[704]的parent字段是一个指针的指针,其指向zend_mm_free_block[600]的child[0]字段。
|
|
存入大小为800b、904b、1000b的内存
依次手动调用
用gdb查看heap->large_free_buckets当前的情况
|
|
图示如下:
存入大小为600b、704b的内存
依次手动调用
用gdb查看heap->large_free_buckets当前的情况
|
|
图示如下:
上图包括了 大内存区域 的两种数据结构:树结构和双向链表结构。
相关代码:引用
|
|
END
本章内容较多,可能会比较难理解,通过gdb调试有助于更好的理解。另外前几篇关于ZMM的文章也有助于对本章的理解。
- 分类:
- php