PHP内存机制 垃圾回收机制

PHP不需要显式的对内存进行管理,这些工作都由PHP解释器进行了。由此PHP内部有一个内存管理体系, 它会自动将不再使用的内存垃圾进行释放,php的默认内存大小是32M,在php.ini中memory_limit = 32M

  • memory_get_usage(),这个函数的作用是获取 目前PHP脚本所用的内存大小。
  • memory_get_peak_usage(),这个函数的作用返回 当前脚本到目前位置所占用的内存峰值,这样就可能获取到目前的脚本的内存需求情况。

从开始就有一套属于自己的内存管理机制,在5.3之前使用的是经典的引用计数技术,但引用技术存在一定的技术缺陷,在PHP5.3之后,引入了新的垃圾回收机制,至此,PHP的内存管理机制更加完善
一次性读取超大的文件到内存中,或者出现超大的数组,或者在大循环中的没有及时是放掉不再使用的变量, 这些都有可能会造成内存占用过大而被终止
Fatal error:Allowed memory size of X bytes exhausted (tried to allocate Y bytes)
内存管理一般会包括以下内容:

  •     是否有足够的内存供我们的程序使用;
  •     如何从足够可用的内存中获取部分内存;
  •     对于使用后的内存,是否可以将其销毁并将其重新分配给其它程序使用。

PHP底层对内存的管理, 围绕着小块内存列表(free_buckets)、 大块内存列表(large_free_buckets)和剩余内存列表(rest_buckets)三个列表来分层进行的。 ZendMM向系统进行的内存申请,并不是有需要时向系统即时申请,而是由ZendMM的最底层(heap层)先向系统申请一大块的内存,通过对上面三种列表的填充,建立一个类似于内存池的管理机制。 在程序运行需要使用内存的时候,ZendMM会在内存池中分配相应的内存供使用。这样做的好处是避免了PHP向系统频繁的内存申请操作

PHP对内存的分配,是结合PHP的用途来设计的,PHP一般用于web应用程序的数据支持,单个脚本的运行周期一般比较短(最多达到秒级),内存大块整块的申请,自主进行小块的分配, 没有进行比较复杂的不相临地址的空闲内存合并,而是集中再次向系统请求。 这样做的好处就是运行速度会更快,缺点是随着程序的运行时间的变长,内存的使用情况会“越来越多”(PHP5.2及更早版本)。 所以PHP5.3之前的版本并不适合做为守护进程长期运行。

销毁
ZendMM在内存销毁的处理上采用与内存申请相同的策略,当程序unset一个变量或者是其他的释放行为时, ZendMM并不会直接立刻将内存交回给系统,而是只在自身维护的内存池中将其重新标识为可用,按照内存的大小整理到上面所说的三种列表(small,large,free)之中,以备下次内存申请时使用。

var_dump(memory_get_usage());   //获取内存
$a = "laruence";                //定义一个变量
var_dump(memory_get_usage());   //定义变量之后获取内存
unset($a);                      //删除该变量
var_dump(memory_get_usage());   //删除变量后获取内存

从上面可以看出php的内存管理机制是:预先给出一块空间,用来存储变量,当空间不够时,再申请一块新的空间

1.存储变量名,存在符号表。

2.变量值存储在内存空间。

3.在删除变量的时候,会将变量值存储的空间释放,而变量名所在的符号表不会减小。

var_dump(memory_get_usage());  //获取内存
//定义100个变量
for($i=0;$i<100;$i++)
{
    $a = "test".$i;
    $$a = "hello";
}
//获取定义100个变量之后的内存
var_dump(memory_get_usage());
//定义100个变量并删除
for($i=0;$i<100;$i++)
{
    $a = "test".$i;
    unset($$a);
}
//获取删除之后的内存
var_dump(memory_get_usage());


从上面可以看出,虽然删除后内存变小了,但还是比没定义变量之前时大,这是因为虽然删除了变量的值,但变量名没有被删除,变量名也要占内存

php垃圾回收机制

每个php变量存在一个叫"zval"的变量容器中。一个zval变量容器,除了包含变量的类型,还包括两个字节的额外信息。第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。通过这个字节,php引擎才能把普通变量和引用变量区分开来,由于php允许用户通过使用&来使用自定义引用,zval变量容器中还有一个内部引用计数机制,来优化内存使用。第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。

$a = 1;
xdebug_debug_zval('a');
echo PHP_EOL;


将变量a的值赋给变量b,变量b不会立刻去在内存中存储值,而是先指向变量a的值,一直到变量a有任何操作的时候

$b = $a;
xdebug_debug_zval('a');
echo PHP_EOL;


因为程序又操作了变量a,所以变量b会自己申请一块内存将值放进去。所以变量a的zavl容器中refcount会减1变为1,变量c指向a,所以refcount会加1变为2

$c = &$a;
xdebug_debug_zval('a');
echo PHP_EOL;
xdebug_debug_zval('b');
echo PHP_EOL;


 

垃圾回收:

1.在5.2版本或之前版本,PHP会根据refcount值来判断是不是垃圾

如果refcount值为0,PHP会当做垃圾释放掉。这种回收机制有缺陷,对于环状引用的变量无法回收

2.在5.3之后版本改进了垃圾回收机制

如果发现一个zval容器中的refcount在增加,说明不是垃圾

如果发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收

如果发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象。当缓冲区达到最大值后,回收算法会循环遍历zval变量容器,判断其是否为垃圾,并进行释放处理。

何时清除

通过上面的算法疑似垃圾会存放到一个区域(垃圾站),只有垃圾站满了才会立刻清除。 注意前提是开启垃圾回收

开启垃圾回收两种方式

  1. php.ini 下的 zend.enable_gc = On 默认开启

  2. 通过 gc_enable() 和 gc_disable() 来打开或关闭垃圾回收

可以直接使用 gc_collect_cycles() 函数强制执行周期回收

最后说了那么多,其实只需要了解其中的原理,整个过程不需要PHP开发人员参与,只需要调用 gc_enable() 或 gc_collect_cycles() 即可实现自动回收

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值