前言:之前对PHP的GC只是了解了个大概,这次详细了解下PHP的垃圾回收机制(GC)。
   介于网上大部分都是PHP5.X的GC,虽然 php5 到 php7 GC部分做出的改动较小,但我觉得还是一起写下来比较好

一、原理

php5和php7的垃圾回收机制都是利用引用计数

二、php5和php7不同点

1、PHP5标量数据类型会计数,PHP7标量数据类型不再计数,不需要单独分配内存
2、PHP7的zval 需要的内存不再是单独从堆上分配,不再自己存储引用计数。
3、PHP7的复杂数据类型(比如数组和对象)的引用计数由其自身来存储。

三、变量在zval的变量容器中结构

zval中,除了存储变量的类型和值之外,还有is_ref字段和refcount字段
1、is_ref:是个bool值,用来区分变量是否属于引用集合。
2、refcount:计数器,表示指向这个zval变量容器的变量个数。

四、PHP5.3标量在zval容器例子

注意:php5.3中将一个变量 = 赋值给另一个变量时,不会立即为新变量分配内存空间,而是在原变量的zval中给refcount加1。 只有当原变量或者发生改变时,才会为新变量分配内存空间,同时原变量的refcount减 1 。当然,如果unset原变量,新变量直接就使用原变量的zval而不是重新分配。&引用赋值时,原变量的is_ref  加1.  如果给一个变量&赋值,之前 = 赋值的变量会分配空间。

<?php
$a = 1;
xdebug_debug_zval('a');
echo PHP_EOL;
$b = $a;
xdebug_debug_zval('a');
echo PHP_EOL; $c = &$a;
xdebug_debug_zval('a');
echo PHP_EOL; xdebug_debug_zval('b');
echo PHP_EOL; 结果如下:

a:(refcount=1, is_ref=0),int 1

a:(refcount=2, is_ref=0),int 1

a:(refcount=2, is_ref=1),int 1

b:(refcount=1, is_ref=0),int 1

五、PHP7.X 标量在zval容器例子

<?php

$a = 1;
xdebug_debug_zval('a');
echo PHP_EOL;
$b = $a;
xdebug_debug_zval('a'); 结果如下:可以看到标量(布尔,字符串,整形,浮点型)不再计数了

六、PHP5.3复合类型数组和对象在zval容器例子

<?php
$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
echo PHP_EOL;
class Test{
public $a = 1;
public $b = 2; function handle(){
echo 'hehe';
}
} $test = new Test();
xdebug_debug_zval('test'); 结果如下:可以看出,数组用了比数组长度多1个zval存储。数组分配了三个zval容器:a   meaning  number

a:(refcount=1, is_ref=0),

array
'meaning' => (refcount=1, is_ref=0),

string

'life' (length=4)
  'number' => (refcount=1, is_ref=0),

int

 42

test:(refcount=1, is_ref=0),

object(Test)[1]
public 'a' => (refcount=2, is_ref=0),

int

 1
  public 'b' => (refcount=2, is_ref=0),

int

2

七、PHP7.X复合类型数组和对象在zval容器例子

<?php

$a = array( 'meaning' => 'life', 'number' => 42 );
xdebug_debug_zval( 'a' );
echo PHP_EOL;
class Test{
public $a = 1;
public $b = 2; function handle(){
echo 'hehe';
}
} $test = new Test();
xdebug_debug_zval('test'); 结果如下:可以明显的看到数组a的refcount=2,后经测试发现数组的refcount都是从2开始的

八、循环引用问题

  1、PHP7.1效果

<?php

$a = array('life');
xdebug_debug_zval( 'a' );
echo PHP_EOL;
$a[] = &$a;
xdebug_debug_zval('a');

可以看到,箭头方向表示的就是递归循环引用了

  2、再看看5.3的效果

  

说明:在5.2及更早版本的PHP中,没有专门的垃圾回收器GC(Garbage Collection),引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,
   如果refcount为0,那么变量的空间可以被释放,否则就不释放,这是一种非常简单的GC实现。现在unset ($a),那么array的refcount减1变为1.现在无任何变量指向这个zval,
   而且这个zval的计数器为1,不会回收。 结果:尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于子元素“1”仍然指向数组本身,所以这个容器不能被清除 。
   因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。 在php5.3的GC中,针对的垃圾做了如下说明:
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()开启和关闭。

九、垃圾回收算法

1、对每个根缓冲区中的根zval按照深度优先遍历算法遍历所有能遍历到的zval,并将每个zval的refcount减1,同时为了避免对同一zval多次减1(因为可能不同的根能遍历到同一个zval),
  每次对某个zval减1后就对其标记为“已减”。 2、再次对每个缓冲区中的根zval深度优先遍历,如果某个zval的refcount不为0,则对其加1,否则保持其为0。 3、清空根缓冲区中的所有根(注意是把这些zval从缓冲区中清除而不是销毁它们),然后销毁所有refcount为0的zval,并收回其内存。 如果不能完全理解也没有关系,只需记住PHP5.3的垃圾回收算法有以下几点特性: 1、并不是每次refcount减少时都进入回收周期,只有根缓冲区满额后在开始垃圾回收。 2、可以解决循环引用问题。 3、可以总将内存泄露保持在一个阈值以下。

 以上就是全部内容了

PHP 垃圾回收机制详解的更多相关文章

  1. JVM的垃圾回收机制详解和调优

    JVM的垃圾回收机制详解和调优 gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都 ...

  2. PHP的垃圾回收机制详解

    原文:PHP的垃圾回收机制详解 最近由于使用php编写了一个脚本,模拟实现了一个守护进程,因此需要深入理解php中的垃圾回收机制.本文参考了PHP手册. 在理解PHP垃圾回收机制(GC)之前,先了解一 ...

  3. java面试题之----JVM架构和GC垃圾回收机制详解

    JVM架构和GC垃圾回收机制详解 jvm,jre,jdk三者之间的关系 JRE (Java Run Environment):JRE包含了java底层的类库,该类库是由c/c++编写实现的 JDK ( ...

  4. GC垃圾回收机制详解

    JVM堆相关知识    为什么先说JVM堆?  JVM的堆是Java对象的活动空间,程序中的类的对象从中分配空间,其存储着正在运行着的应用程序用到的所有对象.这些对象的建立方式就是那些new一类的操作 ...

  5. Python垃圾回收机制详解

    一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题. 在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存. #e ...

  6. JVM的内存区域划分以及垃圾回收机制详解

    在我们写Java代码时,大部分情况下是不用关心你New的对象是否被释放掉,或者什么时候被释放掉.因为JVM中有垃圾自动回收机制.在之前的博客中我们聊过Objective-C中的MRC(手动引用计数)以 ...

  7. php5.3新垃圾回收机制详解

    php的垃圾回收机制主要参考了http://blog.csdn.net/phpkernel/article/details/5734743 这文章. 变量对应的值,比如 $a="abc&qu ...

  8. Python垃圾回收机制详解转自--Kevin Lu

    一.垃圾回收机制 Python中的垃圾回收是以引用计数为主,分代收集为辅.引用计数的缺陷是循环引用的问题. 在Python中,如果一个对象的引用数为0,Python虚拟机就会回收这个对象的内存. #e ...

  9. Java垃圾回收机制详解和调优

    gc即垃圾收集机制是指jvm用于释放那些不再使用的对象所占用的内存.java语言并不要求jvm有gc,也没有规定gc如何工作.不过常用的jvm都有gc,而且大多数gc都使用类似的算法管理内存和执行收集 ...

随机推荐

  1. Jmeter吞吐量控制器

    吞吐量控制器 场景: 假如有两个业务分别是A, B在同一线程组内有10并发, 7个做A业务, 3个做B业务,吞吐量控制器比较推荐使用. 添加吞吐量控制器 ​ 用法1: Percent Executio ...

  2. oracle dg状态检查及相关命令

    oracle dg 状态检查 先检查备库的归档日志同步情况 SELECT NAME,applied FROM v$archived_log; alter database recover manage ...

  3. windows及linux环境下修改pip的默认镜像源的方法

    1. 在windows环境下 临时修改 使用清华大学的源安装numpy包. pip install numpy -i https://pypi.tuna.tsinghua.edu.cn/simple ...

  4. centos7 安装gitlab及简单配置

    1.安装 wget -O gitlab.rpm https://packages.gitlab.com/gitlab/gitlab-ce/packages/el/7/gitlab-ce-11.11.3 ...

  5. 通过premake生成vs工程文件

    visual studio的工程视图,在引用外部目录时非常麻烦,这时候可以使用premake一键生成工程文件,自动配置好工程的各种属性,还有目录的组织结构. 示例:如下是一个c++的外部目录结构,我们 ...

  6. 2. chromium开发工具--gclient

    1.gclient简介 gclient是谷歌开发的一套跨平台git仓库管理工具,用来将多个git仓库组成一个solution进行管理.总体上,其核心功能是根据一个Solution的DEPS文件所定义的 ...

  7. pdfium 代码执行流程

    1.FPDF_InitLibrary(NULL); CPDF_CustomAccess::CPDF_CustomAccess(FPDF_FILEACCESS* pFileAccess) {     i ...

  8. Dubbo支持的注册中心(二)

    1. Zookeeper 优点:支持网络集群 缺点:稳定性受限于 Zookeeper 2. Redis 优点:对服务器环境要求较高 缺点:对服务器环境要求较高 3. Multicast 优点:去中心化 ...

  9. Linux for Matlab中文注释乱码(亲测有效)

    中文注释乱码的原因是windows下的m文件采用的是gb2312编码,只要将所有的m文件转成 utf8文件,显示就正常了. 1.首先安装enca:sudo apt-get install enca 2 ...

  10. Dubbo服务集群容错

    Dubbo是Alibaba开源的分布式服务框架,我们可以非常容易地通过Dubbo来构建分布式服务,并根据自己实际业务应用场景来选择合适的集群容错模式,这个对于很多应用都是迫切希望的,只需要通过简单的配 ...