最新消息:欢迎加入小松的QQ群一起讨论一起学习,本站启用elasticsearch全文检索系统,提供搜索的精确度

php底层GC垃圾回收机制初探

PHP 1045浏览 0评论

今天看到一篇讲php GC垃圾回收机制的文章,自己也学习一下,以前接触php底层的东西不多,写这篇文章用来总结自己学习的知识

在php5.2以及更早的PHP版本中,没有专门的垃圾回收器GC。php引擎在判断一个变量空间是否能够被释放的时候是依据这个变量的zval的refcount的值,
举例说明一下

<?php
$a = "new string"; //$a变量内部存储信息为 a: (refcount=1, is_ref=0)='new string'
$b = $a;           //当把$a赋值给另外一个变量的时候,$a对应的zval的refcount会加1 a,b: (refcount=2, is_ref=0)='new string'
unset($b);         //当我们用unset删除$b变量的时候,$b对应的zval的refcount会减少1a: (refcount=1, is_ref=0)='new string'
?>

如果refcount为0,那么变量的空间可以被释放,否则就不释放,这是一种非常简单的GC实现.

这种机制遇到下面的情况就会出现内容溢出

<?php
$a = array( 'one' );
$a[] =& $a;
/*
a: (refcount=2, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=2, is_ref=1)=...
)
*/
unset($a);

GC垃圾回收机制

由于数组元素“1”仍然指向数组本身,所以这个zval容器不能被清除,我们一般叫做垃圾,这种情况如果在一个循环里这样的内存泄露将会带来很大的风险,有可能将系统资源消耗殆尽,或者服务不可用
php5.3之后的解决方案
首先我们有几个基本的准则:
1:如果一个zval的refcount增加,那么此zval还在使用,不属于垃圾
2:如果一个zval的refcount减少到0, 那么zval可以被释放掉,不属于垃圾
3:如果一个zval的refcount减少之后大于0,那么此zval还不能被释放,此zval可能成为一个垃圾

zval节点放入一个节点(root)缓冲区(root buffer),并且将这些zval节点标记成紫色,同时算法必须确保每一个zval节点在缓冲区中之出现一次。当缓冲区被节点塞满的时候,GC才开始开始对缓冲区中的zval节点进行垃圾判断。

算法以深度优先对每一个节点所包含的zval进行减1操作,为了确保不会对同一个zval的refcount重复执行减1操作,一旦zval的refcount减1之后会将zval标记成灰色。需要强调的是,这个步骤中,起初节点zval本身不做减1操作,但是如果节点zval中包含的zval又指向了节点zval(环形引用),那么这个时候需要对节点zval进行减1操作。

算法再次以深度优先判断每一个节点包含的zval的值,如果zval的refcount等于0,那么将其标记成白色(代表垃圾),如果zval的refcount大于0,那么将对此zval以及其包含的zval进行refcount加1操作,这个是对非垃圾的还原操作,同时将这些zval的颜色变成黑色(zval的默认颜色属性)

最后释放垃圾

QQ交流群:136351212

如无特别说明,本站文章皆为原创,若要转载,务必请注明以下原文信息:
转载保留版权:小松博客» php底层GC垃圾回收机制初探
本文链接地址:https://www.phpsong.com/541.html

发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
木有头像就木有JJ!点这里按步骤申请Gravatar头像吧!