<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; emalloc</title>
	<atom:link href="https://www.phppan.com/tag/emalloc/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 25 Apr 2026 00:56:17 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>PHP源码阅读笔记三十二：PHP内存池中的emalloc/efree层与堆(heap)层</title>
		<link>https://www.phppan.com/2010/11/php-source-code-32-memory-pool-emalloc-efree/</link>
		<comments>https://www.phppan.com/2010/11/php-source-code-32-memory-pool-emalloc-efree/#comments</comments>
		<pubDate>Sun, 21 Nov 2010 14:30:28 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[efree]]></category>
		<category><![CDATA[emalloc]]></category>
		<category><![CDATA[PHP内存池]]></category>
		<category><![CDATA[PHP源码]]></category>

		<guid isPermaLink="false">http://www.phppan.com/?p=1145</guid>
		<description><![CDATA[PHP源码阅读笔记三十二：PHP内存池中的emalloc/efree层与堆(heap)层 emalloc/ef [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>PHP源码阅读笔记三十二：PHP内存池中的emalloc/efree层与堆(heap)层<br />
emalloc/efree层是整个内存体系中最上层结构，它通过与堆层的交换使用PHP自带的内存管理机制。如果有设置USE_ZEND_ALLOC为0，则直接使用malloc/free等函数直接操作内存。<br />
这里将从emalloc与efree两个函数的实现解析emalloc/efree层与堆层的交互，及堆层对于内存的管理机制。<br />
<br /><strong>【emalloc】</strong><br />
emalloc函数是从zend_alloc.h 70行开始。<br />
emalloc是一个宏，其对应了_emalloc函数。<br />
在_emalloc函数中，如果未使用zend的内存管理机制，则直接调用malloc函数，否则调用_zend_mm_alloc_int</p>
<p><strong>[emalloc() -> _emalloc() -> _zend_mm_alloc_int() ]</strong><br />
在_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()</p>
<p><strong>[emalloc() -> _emalloc() -> _zend_mm_alloc_int() -> zend_mm_search_large_block()]</strong><br />
zend_mm_search_large_block函数用来在large_free_buckets中查找合适的内存块。其中当对于ZEND_MM_LARGE_BUCKET_INDEX(true_size)大小的没有找到时，需要查找更大块列表中的最小块。</p>
<p>如果在大块列表和小块列表中都没有，则需要从剩余列表块中查找，如果找到，则同样跳转到zend_mm_finished_searching_for_block<br />
如果三个列表中都没有找到，则需要重新增加内存分配。此时调用storage层的分配函数进行分配，其中内存的大小，如果需要分配的内存大于block_size，则需要根据大小重新计算，否则直接分配block_size大小的内存。<br />
分配内存完后，需要重新整理堆，此时需要重新计算堆中的内存大小，将新分配的内存添加到segments_list的前面。</p>
<p>如果在上面的操作中是直接跳转到zend_mm_finished_searching_for_block，则需要将使用了的内存块从对应的列表中移除（此处应该是一个标记的过程，伪移除）</p>
<p>接下来，根据剩下的内存大小，将其移到空闲列表或剩余列表。</p>
<p>最后返回分配的块。</p>
<p>在emalloc整个过程中，有以下一些注意点。<br />
ZEND_MM_BUCKET_INDEX(true_size)定位在bucket中的位置，这个值大于等于0，小于32。<br />
其实现如下：<br />
#define ZEND_MM_BUCKET_INDEX(true_size)                ((true_size>>ZEND_MM_ALIGNMENT_LOG2)-(ZEND_MM_ALIGNED_MIN_HEADER_SIZE>>ZEND_MM_ALIGNMENT_LOG2))<br />
free_bitmap和large_free_bitmap的值都是0到31。</p>
<p><strong>【efree】</strong><br />
efree函数是从zend_alloc.h 72行开始。<br />
efree是一个宏，其对应了_efree函数。<br />
在_efree函数中，如果未使用zend的内存管理机制，则直接调用free函数，否则调用_zend_mm_free_int</p>
<p><strong>[efree() -> _efree() -> _zend_mm_free_int() ]</strong><br />
堆首先将整个堆的大小减少，如果当前块的后一个块是空闲块，则将后一个空闲块从空闲块列表中删除并与当前块合并，如果当前块的前一个块是空闲块，则将前一个空闲块从空闲块列表中删除并与当前块合并，指针指向前一个空闲块。如果此时当前块是开始的块，则调用zend_mm_del_segment将整段内存清除，如果不是开始块，则将合并后的块添加到空闲块列表。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2010/11/php-source-code-32-memory-pool-emalloc-efree/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
