学习PHP底层,探究内存管理与缓存机制
Posted PHP自学中心
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习PHP底层,探究内存管理与缓存机制相关的知识,希望对你有一定的参考价值。
文章来自:https://blog.csdn.net/chenrui310/article/details/100578777
点击加入:
技术交流微信群
我们在学习中单枪匹马,还不如一次短短的交流,你可以在别人吸取各种学习经验。 学习方法以及学习技巧,所以,学习与交流少不了一个圈子,提升你的学习技能。 请点击加技术群:PHP自学中心交流群
视频教程分享
1 Linux从零入门实战-2019年七月Z线
公众号里回复:08250023
2 Git版本管理视频教程
公众号里回复:20190102
3 web前端视频教程(基础+中级+高级)
公众号里回复:20181226
4 Laravel5.x底层实战兼核心源码解析
链接:http://www.mano100.cn/thread-344-1-1.html
5 由浅入深析Thinkphp5和ThinkPHP6底层源码
链接:http://www.mano100.cn/thread-1-1-1.html
6 全方位深度剖析PHP7底层源码(完整版)
链接:http://www.mano100.cn/thread-93-1-1.html
精选文章正文
PHP在运行时所需的内存,是一次性向操作系统申请开辟的,而不是分多次。那他是怎么样一次性申请呢,机制又是如何?请看下边介绍。
heap层是PHP内存管理的核心实现,PHP底层对内存的管理, ZendMM向系统进行的内存申请,并不是有需要时向系统即时申请, 而是由ZendMM的最底层(heap层)先向系统申请一大块的内存, 建立一个类似于内存池的管理机制,unset后,ZendMM并不会直接立刻将内存交回给系统,而是只在自身维护的内存池(storge层)中将其重新标识为可用,。
优点:
1.预定义常量变量多,对内存的请求有数百次,避免了PHP向系统频繁的内存申请操作,减少了对OS的请求次数。
2.运行速度会更快,缺点是随着程序的运行时间的变长,内存使用越来越多,所以在php5.3时就引入新垃圾回收机制。
详细分析如下:PHP的内存管理可以被看作是分层(hierarchical)的。它分为三层:存储层(storage)、堆层(heap)和接口层(emalloc/efree)。存储层通过 malloc()、mmap() 等函数向系统真正的申请内存,并通过 free() 函数释放所申请的内存。
存储层通常申请的内存块都比较大,这里申请的内存大并不是指storage层结构所需要的内存大, 只是堆层通过调用存储层的分配方法时,其以大块大块的方式申请的内存,存储层的作用是将内存分配的方式对堆层透明化。
如图下所示,PHP内存管理器。
PHP在存储层共有4种内存分配方案: malloc,win32,mmap_anon,mmap_zero, 默认使用malloc分配内存,如果设置了ZEND_WIN32宏,则为windows版本,调用HeapAlloc分配内存, 剩下两种内存方案为匿名内存映射,并且PHP的内存方案可以通过设置环境变量来修改。
一.内存的申请
heap层是PHP内存管理的核心实现,PHP底层对内存的管理, 围绕着小块内存列表(free_buckets)、 大块内存列表(large_free_buckets)和 剩余内存列表(rest_buckets)三个列表来分层进行的。
ZendMM向系统进行的内存申请,并不是有需要时向系统即时申请, 而是由ZendMM的最底层(heap层)先向系统申请一大块的内存,通过对上面三种列表的填充, 建立一个类似于内存池的管理机制。
在程序运行需要使用内存的时候,ZendMM会在内存池中分配相应的内存供使用。这样做的好处是避免了PHP向系统频繁的内存申请操作,如下面的代码:
<?php
$tipi = "o_o
";
echo $tipi;
?>
这是一个简单的php程序,但通过对emalloc的调用计数,只是PHP程序,只赋值了一个变量而已,但是却发现对内存的请求有数百次之多, 当然这非常容易解释,因为PHP脚本的执行,需要大量的环境变量以及内部变量的定义, 这些定义本身都是需要在内存中进行存储的。
在编写PHP的扩展时,推荐使用emalloc(申请的是zend_mm_storage层的内存块)来代替malloc(申请的是操作系统的内存块),其实也就是使用PHP的ZendMM来代替 手动直接调用系统级的内存管理。
ZendMM使用_zend_mm_alloc_int函数进行内存分配,流程如下:
二.内存的销毁
ZendMM在内存销毁的处理上采用与内存申请相同的策略,当程序unset一个变量或者是其他的释放行为时,ZendMM并不会直接立刻将内存交回给系统,而是只在自身维护的内存池(storge层)中将其重新标识为可用, 按照内存的大小整理到上面所说的三种列表(small,large,free)之中,以备下次内存申请时使用。
内存销毁的最终实现函数是_efree。在_efree中,内存的销毁首先要进行是否放回cache的判断。如果内存的大小满足ZEND_MM_SMALL_SIZE并且cache还没有超过系统设置的ZEND_MM_CACHE_SIZE, 那么,当前内存块zend_mm_block就会被放回mm_heap->cache中。
在内存的销毁过程中,还涉及到引用计数和垃圾回收(GC),将在后边小节进行讨论。参见PHP内核--内存泄漏与新垃圾回收机制
三.缓存
从最初始的处理器与内存间的Cache开始,都是为了让数据访问的速度适应CPU的处理速度, 其基于的原理是内存中“程序执行与数据访问的局域性行为”。
同样PHP内存管理中的缓存也是基于“程序执行与数据访问的局域性行为”的原理。
引入缓存,就是为了减少小块内存块的查询次数(查询前先看是否能命中缓存),为最近访问的数据提供更快的访问方式。
PHP将缓存添加到内存管理机制中做了如下一些操作:
1 标识缓存和缓存的大小限制,即何时使用缓存,在某些情况下可以以最少的修改禁用掉缓存。
2 缓存的存储结构,即缓存的存放位置、结构和存放的逻辑。
3 初始化缓存。
4 获取缓存中内容。
5 写入缓存。
释放缓存或者清空缓存列表
缓存本身也是存储在storage层申请的内存中的,如果内存都不够用了,那就得释放缓存啦。
当堆的内存溢出时,程序会调用zend_mm_free_cache释放缓存中。整个释放的过程是一个遍历数组, 对于每个数组的元素程序都遍历其所在链表中在自己之前的元素,执行合并内存操作,减少堆结构中缓存计量数字。
以上是本文的全部内容,希望对大家的学习有帮助,也希望大家多多支持 php自学中心 ,学习与交流少不了一个圈子,点击加技术群:
以上是关于学习PHP底层,探究内存管理与缓存机制的主要内容,如果未能解决你的问题,请参考以下文章