• php垃圾回收机制简介


    参考 http://php.net/

    php zval数据结构

    struct _zval_struct {
        zvalue_value value;     /* value */
        zend_uint refcount__gc;  /* variable ref count */
        zend_uchar type;          /* active type */
        zend_uchar is_ref__gc;    /* if it is a ref variable */
    };
    typedef struct _zval_struct zval;
    1.第一个是"is_ref",是个bool值,用来标识这个变量是否是属于引用集合(reference set)。
    2.第二个额外字节是"refcount",用以表示指向这个zval变量容器的变量(也称符号即symbol)个数。

    第一个例子,使用xdebug查看 zval变量容器的内部数据结构。
    <?php
    $a = "new string";
    ?>

    <?php
    xdebug_debug_zval('a');
    ?>
    a: (refcount=1, is_ref=0)='new string'

    第二个例子,
    增加一个zval的引用计数,通过赋值观察refcount的变化
    <?php
    $a = "new string";
    $b = $a;
    xdebug_debug_zval( 'a' );
    ?>
    a: (refcount=2, is_ref=0)='new string'
    第三个例子,减少引用计数来观察zval数据结构内部的变化
    <?php
    $a = "new string";
    $c = $b = $a;
    xdebug_debug_zval( 'a' );
    unset( $b, $c );
    xdebug_debug_zval( 'a' );
    ?>
    输出
    a: (refcount=3, is_ref=0)='new string'
    a: (refcount=1, is_ref=0)='new string'

    复合数据类型
    <?php
    $a = array( 'meaning' => 'life', 'number' => 42 );
    xdebug_debug_zval( 'a' );
    ?>
    输出:
    a: (refcount=1, is_ref=0)=array (
       'meaning' => (refcount=1, is_ref=0)='life',
       'number' => (refcount=1, is_ref=0)=42
    )

    接下来是一个很经典的说明zval内部指针关系的例子:

    <?php
    $a = array( 'meaning' => 'life', 'number' => 42 );
    $a['life'] = $a['meaning'];
    xdebug_debug_zval( 'a' );
    ?>

    输出:

    a: (refcount=1, is_ref=0)=array (
       'meaning' => (refcount=2, is_ref=0)='life',
       'number' => (refcount=1, is_ref=0)=42,
       'life' => (refcount=2, is_ref=0)='life'
    )
    图:
    接下来就是一个会在php5.3版本之前导致内存泄漏的一个例子
    <?php
    $a = array( 'one' );
    $a[] =& $a;
    xdebug_debug_zval( 'a' );
    ?>
    输出:
    a: (refcount=2, is_ref=1)=array (
       0 => (refcount=1, is_ref=0)='one',
       1 => (refcount=2, is_ref=1)=...
    )
    上面的输出结果中的"..."说明发生了递归操作, 显然在这种情况下意味着"..."指向原始数组
    图:

    尽管不再有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素“1”仍然指向数组本身,所以这个容器不能被清除 。因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。

    php的同步算法处理引用内存泄漏的方法回头再更(暂时没有深入看)

    回收周期

    php会把可能根(疑似垃圾的跟)放在根缓存区里面(默认大小为10000),调用gc_enable() 和 gc_disable()函数来打开和关闭垃圾回收机制。

    但是即使关闭了垃圾回收机制,可能根还是会存进根缓存区里面(相比每次检查回收机制是否打开,还不如存进去),但是当缓存区存满之后,如果还有疑似根就不会存进去了,可能造成内存泄漏。

    因此 就在你调用gc_disable()函数释放内存之前,先调用gc_collect_cycles()函数可能比较明智。因为这将清除已存放在根缓冲区中的所有可能根,然后在垃圾回收机制被关闭时,可留下空缓冲区以有更多空间存储可能根。

    垃圾回收会带来时间成本的增加,约百分之10(不到)。但是内存溢出会有明显抑制(特别是在大量多个对象互相指向的时候)

    在php5.3以上版本,如果发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的可疑对象。

    具体参看PHP官网 http://php.net/manual/zh/features.gc.performance-considerations.php

    
    
    
    
     
  • 相关阅读:
    关于线程间通信的条件变量
    vim学习相关链接
    CString与输入输出流对象问题。
    CRect类 的介绍
    在vs中char类型的实参与LPCWSTR类型的形参类型不兼容怎么解决?
    ADO Recordset 对象链接
    FIND_IN_SET的简单使用
    html meta标签作用
    github新建托管项目及上传项目
    Javascript编码规范
  • 原文地址:https://www.cnblogs.com/tobemaster/p/8180091.html
Copyright © 2020-2023  润新知