php 垃圾回收机制

理解PHP垃圾回收机制(GC)之前,先了解一下变量的存储。

在php 手册中已经讲的很清楚了

基础定义:

https://www.php.net/manual/zh/features.gc.refcounting-basics.php  可以去这里翻翻手册看一下

简单的概述一下

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

所以在此不再过多的解释php 变量。

在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,如果refcount为0,那么变量的空间可以被释放,否则就不释放,这是一种非常简单的GC实现,这是引用计数内存机制

那为什么会需要垃圾回收呢?

因为在php中存在环状引用导致内存泄露,在之前的5.2 是回收不了的

问题:什么样的情况下存在环状引用呢?

答:当两个或多个对象互相引用形成环状后,内存对象的计数器则不会消减为0;这时候,这一组内存对象已经没用了,但是不能回收,从而导致内存泄露。

PHP5.3中,采用了专门的算法来解决此事

  1. 如果一个zval的refcount增加,那么此zval还在使用,肯定不是垃圾,不会进入缓冲区。
  2. 如果一个zval的refcount减少到0, 那么zval会被立即释放掉,不属于GC要处理的垃圾对象,不会进入缓冲区。
  3. 如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾,将其放入缓冲区。PHP5.3中的GC针对的就是这种zval进行的处理。

如何实现垃圾回收机制呢?

开启/关闭垃圾回收机制可以通过修改php配置实现,也可以在程序中使用gc_enable() 和 gc_disable()开启和关闭。

unset函数的影响

unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1;在上面的例子中,循环体内部,$a=new A(); unset($a);并不会将$a的引用计数减到零;

= null 操作的影响
$a = null 是直接将$a 指向的数据结构置空,同时将其引用计数归0

脚本执行结束的影响
脚本执行结束,该脚本中使用的所有内存都会被释放,不论是否有引用环。

注意:

PHP中的垃圾回收机制,仅仅在循环回收算法确实运行时会有时间消耗上的增加

原文地址:https://www.cnblogs.com/fangdada/p/14882844.html