zoukankan      html  css  js  c++  java
  • 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

    
    
    
    
     
  • 相关阅读:
    SQLServer 获取汉字拼音的首字母(大写)函数
    MySQL动态SQL的拼接以及执行、分页
    Jdbc连接sqlserver,mysql,oracle
    MySQL之排序显示行号
    List的分组,求和,过滤操作
    linux 常用命令集合
    redis 基本类型和命令(一)
    ORCLE 创建表空间,用户,赋予角色以及授权
    游标
    【应用服务 App Service】App Service中上传文件/图片(> 2M)后就出现500错误(Maximum request length exceeded).
  • 原文地址:https://www.cnblogs.com/tobemaster/p/8180091.html
Copyright © 2011-2022 走看看