找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 338|回复: 0
打印 上一主题 下一主题

深入解析PHP垃圾回收机制对内存泄露的处理

[复制链接]

2536

主题

2536

帖子

7532

积分

论坛元老

Rank: 8Rank: 8

积分
7532
跳转到指定楼层
楼主
发表于 2018-2-14 08:20:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

            上次说到了refcount和is_ref,这里来说说内存泄露的情况
[U]复制代码[/U] 代码如下:
$a = array(1, 2, &$a);
unset($a);
在老的PHP版本中,这里就会出现内存泄露,分析如下:
执行第一行,可以知道$a和$a[2]指向的zval refcount=2,is_ref=1
然后执行第二行,$a将会从符号表中被删除,同时指向的zval的refcount--,此时refcount=1,因为refcount!=0,故此zval不会被当做垃圾回收,但是此时我们却失去了$a[2]指向这个zval的入口,因此这个zval成了一块内存垃圾
同样的道理可以发生在类内部引用里,例如
[U]复制代码[/U] 代码如下:
$a = new Man();
$a->self = &$a;
unset($a);
那么如何解决这种问题呢,新的GC机制采用了一个算法来解决这个问题
PHP有一个root buffer用来存储zval的节点信息,当root buffer满了或者手动调用gc函数时,GC算法启动
对于一个数组或者类类型的zval而言,在垃圾回收机制启动时,算法会对该zval的数组/类内部的元素/成员的zval进行一次遍历并将refcount减1,如果说遍历完成后该zval的refcount被减为0,则说明这个zval是一个内存垃圾,他将被销毁,见下面的例子
[U]复制代码[/U] 代码如下:
$a = array(1, 2, &$a, &$a);
unset($a);
容易知道$a指向的zval,假设为z1的refcount=3,is_ref=1
当unset($a)执行的时候,$a就已经从符号表中删去,同时我们也失去了访问z1的入口,此时z1 refcount=2,is_ref=1
当GC启动时,会对该z1的数组元素的zval的refcount进行遍历减1,遍历到a[2]时,z1 refcount--, a[3]时 z1 refcount--,此时z1 refcount = 0,即可将z1标记为内存垃圾,算法后将其回收
总结来说可以这么表述:若一个数组类型的zval,对他的元素zval进行一次遍历,同时将遍历到的zval的refcount--,如果最后refcount=0的zval,就是垃圾,需要被回收
            
            
您可能感兴趣的文章:
  • javascript 内存回收机制理解
  • 从JVM的内存管理角度分析Java的GC垃圾回收机制
  • 跟我学习javascript的垃圾回收机制与内存管理
  • Android垃圾回收机制解决内存泄露问题
  • 深入理解Java垃圾回收机制以及内存泄漏
  • 图文详解java内存回收机制
            
  • 分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    用户反馈
    客户端