PHP内存机制

是否有足够的内存供我们的程序使用;

如何从足够可用的内存中获取部分内存;

对于使用后的内存,是否可以将其销毁并将其重新分配给其它程序使用。

与此对应,PHP的内容管理也包含这样的内容,只是这些内容在ZEND内核中是以宏的形式作为接口提供给外部使用。后面两个操作分别对应emalloc宏,efree宏,而第一个操作可以根据emalloc宏返回结果检测。

PHP的内存管理可以被看作是分层(hierarchical)的。它分为三层:存储层(storage)、堆层(heap)和接口层(emalloc/efree)。存储层通过 malloc、mmap等函数向系统真正的申请内存,并通过 free 函数释放所申请的内存。存储层通常申请的内存块都比较大,这里申请的内存大并不是指storage层结构所需要的内存大,只是堆层通过调用存储层的分配方法时,其以大块大块的方式申请的内存,存储层的作用是将内存分配的方式对堆层透明化。如图6.1所示,PHP内存管理器。PHP在存储层共有4种内存分配方案: malloc,win32,mmap_anon,mmap_zero,默认使用malloc分配内存,如果设置了ZEND_WIN32宏,则为windows版本,调用HeapAlloc分配内存,剩下两种内存方案为匿名内存映射,并且PHP的内存方案可以通过设置环境变量来修改。

当初始化内存管理时,调用函数是zend_mm_startup。它会初始化storage层的分配方案,初始化段大小,压缩边界值,并调用zend_mm_startup_ex初始化堆层。它对应的环境变量名为:ZEND_MM_MEM_TYPE。这里的初始化的段大小可以通过ZEND_MM_SEG_SIZE设置,如果没设置这个环境变量,程序中默认为256 * 1024。这个值存储在_zend_mm_heap结构的block_size字段中,将来在维护的三个列表中都没有可用的内存中,会参考这个值的大小来申请内存的大小。

PHP中的内存管理主要工作就是维护三个列表:小块内存列表(free_buckets)、大块内存列表(large_free_buckets)和剩余内存列表(rest_buckets)。看到bucket这个单词是不是很熟悉?在前面我们介绍HashTable时,这就是一个重要的角色,它作为HashTable中的一个单元角色。在这里,每个bucket也对应一定大小的内存块列表,这样的列表都包含双向链表的实现。

我们可以把维护的前面两个表看作是两个HashTable,那么,每个HashTable都会有自己的hash函数。首先我们来看free_buckets列表,这个列表用来存储小块的内存分配

我们通过一次列表的元素插入操作来理解列表的结果。首先确定当前需要内存所在的数组元素位置,然后查找此内存大小所在的位置。这个查找行为是发生在树型结构中,而树型结构的位置与内存的大小有关。其查找过程如下:

第一步 通过索引获取树型结构第一个结点并作为当前结点,如果第一个结点为空,则将内存放到第一个元素的结点位置,返回,否则转第二步

第二步 从当前结点出发,查找下一个结点,并将其作为当前结点

第三步 判断当前结点内存的大小与需要分配的内存大小是否一样如果大小一样则以双向链表的结构将新的元素添加到结点元素的后面第一个元素的位置。否则转四步

第四步 判断当前结点是否为空,如果为空,则占据结点位置,结束查找,否则第二步。

我们可以看到PHP在存储层共有4种内存分配方案: malloc,win32,mmap_anon,mmap_zero默认使用malloc分配内存,如果设置了ZEND_WIN32宏,则为windows版本,调用HeapAlloc分配内存,剩下两种内存方案为匿名内存映射,并且PHP的内存方案可以通过设置变量来修改。

添加下方微信获取更多教程与资源

我们一起学习与交流

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180717B17W4L00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券