1,介绍

php的垃圾回收机制(GC)是在PHP5之后出现的,而在PHP5.3版本之前使用的都是“引用计数”的方式。实现引用计数的实质就是在每个内存对象中都有一个计数器,当内存对象被变量引用时,计数器+1,当变量取消或更改引用内存时,计数器-1,直到计数器中的值为0时,说明该内存对象没有被变量引用,,就产生了一个无意义的内存对象。php就会销毁释放内存,进行垃圾回收。

2,实现

每个变量被赋值时就会生成叫‘zval’的变量容器,‘zavl’容器中除了包含变量名,变量的类型和变量的值以外,还包含两个字节的额外信息。第一个是"is_ref",是个布尔值,用来表示该变量是否被引用,php就是根据这个判断变量是否是普通类型还是引用类型;另一个是‘refcount’,功能类似于计数器,记录指向该变量容器的变量个数。

1,生成并显示一个新的zval容器

$a;
xdebug_debug_zval('a');//a: no such symbo
$b="new string";
xdebug_debug_zval('b');//b: (refcount=1, is_ref=0),

可以看到:变量赋值后生成的‘zavl’容器中的参数。其中refcount=1表示一个变量指向该变量容器。

2,添加一个‘zavl’的引用计数

$b="new string";
xdebug_debug_zval('b');
$c=$b;
xdebug_debug_zval('b');//b: (refcount=2, is_ref=0),string 'new string' (length=10)
$d="new string";
xdebug_debug_zval('d');//d: (refcount=1, is_ref=0),

这时,引用次数是2,因为同一个变量容器被变量b和变量c关联。当将一个变量赋值给另一个变量时,php不会去复制已生成的变量容器。而将一个值赋值给一个变量时,会重新生成一个新的‘zavl’容器。

3,清空并删除一个引用计数

$b="new string";
$c=$b;
unset($b);
xdebug_debug_zval('c');//c:(refcount=1, is_ref=0),string 'new string' (length=10)
unset($c);
xdebug_debug_zval('c');//c: no such symbol

当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束),或者对变量调用了函数 unset()时,”refcount“就会减1。当refcount=0时,包含类型和值的这个变量容器就会从内存中删除。

上面的数据类型都是标量数据类型,而复合数据类型(array,object)又有不同。

4,生成一个复合数据的变量容器

$arr=[];
xdebug_debug_zval('arr');
$array=['name'=>'张三','age'=>'18'];
xdebug_debug_zval('array');

结果如下:

图示:

可以看到:数组分配了三个zval容器:array   name  age

5,添加一个已经存在的元素到数组中

$array = [
'name' => '张三',
'age' => '18'
];
$array['zhangsan'] = $array['name'];
xdebug_debug_zval('array');

6,销毁包含数组名信息的'zavl'变量容器

$array = [
'name' => '张三',
'age' => '18'
];
$array['zhangsan'] = $array['name'];
unset($array);
xdebug_debug_zval('array');

其结果如下

删除数组中的一个元素,就是类似于从作用域中删除一个变量. 删除后,数组中的这个元素所在的容器的“refcount”值减少,同样,当“refcount”为0时,这个变量容器就从内存中被删除。

一般来说,'zavl'容器中的refcount=0时,该变量容器就是垃圾,会被php引擎销毁。但是有一种情况:'zavl'容器中的refcount不为0,却没有变量指向它,仍然是个垃圾。

环状引用就是一个例子,即把数组作为一个元素添加到自己。

7,生成一个包含环状引用的‘zavl’容器

$arr = [
'name' => '张三'
];
$arr[] = &$arr;
xdebug_debug_zval('arr');

结果如下

图示:

8,删除环状引用

$arr = [
'张三'
];
$arr[] = &$arr;
unset($arr);
xdebug_debug_zval('arr');

图示:

现在,虽然没有任何变量指向该‘zavl’,但由于数组元素“0”仍然指向数组本身,所以该‘zavl’不能被清除 。而又因为没有另外的变量指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。庆幸的是,php脚本运行完毕后会清除这个数据结构。但是在php清除之前,将耗费不少空间的内存。而在一般情况下,php脚本运行完毕因此环状引用内存泄露的问题一般只影响长时间运行的程序脚本。并且在5.3版本后垃圾处理虽然其基础仍然是引用计数,但是做了一些改良,能够将环状引用导致的内存泄露控制在一定的规模以内。

当然,我们也可以手动的清除环状结构

9,手动清除环状引用

$arr = [
'张三'
];
$arr[] = &$arr;
$arr = null;
xdebug_debug_zval('arr');
unset($arr);
xdebug_debug_zval('arr');

结果如下

$arr=null后,虽然变量容器‘zavl’还存在,但是之前储存在内存中引用传递的值却是完全删除掉了,最后再使用unset($arr)就可以断开变量名arr和null值之间的联系,令refcount=0就能够释放到内存了。

PHP的垃圾回收机制之引用计数的更多相关文章

  1. Python的垃圾回收机制(引用计数+标记清除+分代回收)

    一.写在前面: 我们都知道Python一种面向对象的脚本语言,对象是Python中非常重要的一个概念.在Python中数字是对象,字符串是对象,任何事物都是对象,而它们的核心就是一个结构体--PyOb ...

  2. Python的垃圾回收机制以及引用计数

    Python中的计数引用 在Python中,由于Python一门动态的语言,内部采用的指针形式对数据进行标记的,并不像c/c++那样,通过指定的数据类型并分配相应的数据空间,Python中定义的变量名 ...

  3. c++垃圾回收代码练习 引用计数

    学习实践垃圾回收的一个小代码 采用引用计数 每次多一个指针指向这个分配内存的地址时候 则引用计数加1 当计数为0 则释放内存 他的难点在于指针之间的复制 所有权交换 计数的变化 #include &l ...

  4. PHP GC垃圾回收机制之引用变量回收周期疑问

    普通的引用变量的销毁大家都知道, 当unset的时候如果refcount = 0 则认为无用, 销毁. 但是手册中提到一点会有递归引用的问题,很是奇葩 代码如下 <?php $a = 1; $a ...

  5. Python垃圾回收详解:引用计数+标记清理+分代回收

    Python采用的是引用计数机制为主,标记-清理和分代收集两种机制为辅的策略. 1.引用计数 python中一切皆对象,所以python底层计数结构地就可以抽象为: 引用计数结构体{ 引用计数; 引用 ...

  6. php 调试工具及学习PHP垃圾回收机制了解引用计数器的概念

    php代码工具:Xdebug  与分析工具 WinCacheGrind Xdebug之函数大全: string xdebug_call_class()返回当前被调用的函数或方法所属的类的类名 stri ...

  7. 学习PHP垃圾回收机制了解引用计数器的概念

    php变量存在一个叫"zval"的变量容器中,"zval"变量容器包括含变量的类型和值,还包括额外的两个字节信息,分别是“is_ref”表示变量是否属于引用,“ ...

  8. python垃圾回收机制与小整数池

    python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...

  9. JavaScript中的垃圾回收机制与内存泄露

    什么是内存泄露? 任何编程语言,在运行时都需要使用到内存,比如在一个函数中, var arr = [1, 2, 3, 4, 5]; 这么一个数组,就需要内存. 但是,在使用了这些内存之后, 如果后面他 ...

随机推荐

  1. GOOD BYE OI

    大米饼正式退役了,OI给我带来很多东西 我会的数学知识基本都在下面了 博客园的评论区问题如果我看到了应该是会尽力回答的... 这也是我作为一个OIer最后一次讲课的讲稿 20190731 多项式乘法 ...

  2. HTML基础知识---文本编辑练习

    飘柔兰花去油洗发水液露去屑止痒控油                                         阿道夫净屑舒爽清洁头皮去屑洗发水520ml                      ...

  3. Spring Boot 知识笔记(配置文件)

    Spring boot 提供了两种常用的配置文件,properties和yml文件. 1.yml yml是YAML(YAML Ain't Markup Language)语言的文件,以数据为中心,比j ...

  4. pacemaker和keepalived的区别

    1.pacemaker Pacemaker 是一款开源的高可用资源管理软件,适合大集群或者小集群. Pacemaker 由Novell支持,SLES HAE就是用Pacemaker来管理集群,并且Pa ...

  5. mac系统中怎么打开rar/zip等压缩文件?

    平常使用mac的同学们,可能经常要接受下别人发过来的rar文件,可惜的时mac os x系统默认是不能打开rar文件(不知道以后苹果会支持rar不?),那么我们该如何去解圧rar文件,接下来我将介绍. ...

  6. 20165230田坤烨网络对抗免考报告_Windows系统提权

    目录 KERNEL EXPLOITATION 服务攻击: DLL劫持 攻击 不安全的服务权限 探测 unquoted path未被引号标记的路径 探测 攻击 服务注册表键 探测 攻击 Named Pi ...

  7. zooKeeper使用记录

    背景:记录zooKeeper使用过程中遇到的问题. 在删除zooKeeper相关节点的时候需要进行权限的认证,下面的连接讲的还是很详细的 zookeeper的ACL权限控制

  8. linux阿里云服务器更换镜像的方法

    linux阿里云服务器更换镜像的方法 1 先进入硬盘创建快照 生成自定义镜像 ps:他可以在阿里云各个服务器上共享 再左侧镜像 点击去可以看到共享 直接进ecs 关闭服务器 重新初始化硬盘 然后主界面 ...

  9. 概率dp - Uva 10900 So you want to be a 2n-aire?

    So you want to be a 2n-aire? Problem's Link Mean: 玩一个答题赢奖金的游戏,一开始有1块钱,玩n次,每次赢的概率为t~1之间的某个实数. 给定n和t,求 ...

  10. 开发dubbo应用程序(二)dubbo注册中心相关概述

    1.注册中心概述 ​ 在Dubbo微服务体系中,注册中心是其核心组件之一.Dubbo通过注册中心实现了分布式环境中各微服务之间的注册与发现,是各分布式节点之间的纽带.其主要作用如下: 动态加入.一个服 ...