• PHP垃圾回收机制


    什么是垃圾?
    垃圾主要是针对内存的,如果一个对象struct,并没有任何变量引用它,那这个对象就是垃圾。

    为啥要清理垃圾?
    不是说php线程结束的时候回销毁所有的变量,关闭所有打开的句柄资源,不都是自动的吗?为什么还需要清理?
    ·如果php开启了很多内存空间,但是却没有销毁它,内存会一点点的被吃掉,最终导致内存溢出。
    ·如果写的php代码是个需要长时间执行的呢,例如弄成守护进程。

    如何回收垃圾?
    第一步:从所有变量中找到垃圾(所有的变量怎么来的?怎样才能知道其中的某个变量是垃圾?)
    第二步:找到垃圾后,清除垃圾(怎么清除?怎样才算真的清除垃圾?)

    1、如何找垃圾
    从所有变量中找到垃圾,所有的变量get_defined_vars函数能够看到所有已经定义的变量,那意味着php本身能存储所有变量或已开辟的内存空间,具体在zend_globals.h中struct _zend_executor_globals中看到

    补充:php变量值存储在struct _zval_struct中,而变量名存储在struct _zend_executor_globals中
    struct _zend_executor_globals {

    /*略*/

    HashTable *active_symbol_table; /* 局部变量的符号表 */
    HashTable symbol_table; /* main symbol table 全局变量的符号表*/

    /*略*/

    这样就能找到所有的变量了,怎样找到垃圾?按照我们的想法,一定会在这个变量上面打个标签,这个是垃圾,可以清理了。那么这个标签在哪里呢?
    在struct _zval_struct中
    zend_uint refcount__gc //用来标记有多少个变量指向它
    zend_uchar is_ref__gc //用来标记是否用引用的方式指向它

    2、如何清理掉
    看看是不是垃圾,就看refcount__gc是不是0,找到0就清除,并回收内存(5.2以及以前版本)
    在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)=...
    )


    能看到数组变量(a)同时也是这个数组的第二个元素(1)指向的变量容器中"refcount"为2。上面的输出结果中的"..."说明发生了递归操作,显然在这种情况下意味着"..."指向原始数组。
    跟刚刚一样,对一个变量调用unset,将删除这个符号,且它指向的变量容器中的引用次数也减1.所以,如果我们执行完上面的代码后,对变量$a调用unset,那么变量$a和数组元素“1”所指向的变量容器的引用次数减1,从“2”变成“1”,如下:
    (refcount=1,is_ref=1)=array(
    0=>(refcount=1,is_ref=0)='one',
    1=>(refcount=1,is_ref=1)=...
    )

    3、引发思考
    尽管不在有某个作用域中的任何符号指向这个结构(就是变量容器),由于数组元素“1”仍然指向数组本身,所以这个容器不能被清除。因为没有另外的符号指向它,用户没有办法清除这个结构,结果就会导致内存泄漏。庆幸的是,php将在脚本执行结束时清除这个数据结构,但是在php清除之前,将想好不少内存。
    如果上面的情况发生仅仅一两次倒没什么,但是如果出现几千次,甚至几十万次的内存泄漏,这显然是个大问题。这样的问题往往发生在长时间运行的脚本中,比如请求基本上不会结束的守护进程或者单元测试中的大的套件中。

    4、php5.3的删除算法介绍
    在php5.3中,采用模拟删除每个疑似变量。模拟删除时将变量引用数减1,然后再进行模拟恢复,但恢复是有条件的,当有其他变量指向该值时才对其做模拟恢复。这样剩下的一对没能恢复的就是该删除的

    5、什么时候回收?
    ·当我们存储的疑似垃圾的区域满了的时候,就会被执行清除垃圾的操作,前提是开启了垃圾回收机制,当然默认是打开的,php.ini设置允许你修改它:zend.enable_gc
    ·修改配置zend.enable_gc,也能通过分别调用gc_enable()和gc_disable()函数来打开和关闭垃圾回收机制。调用这些函数,与修改配置项来打开挥着关闭垃圾回收机制的效果是一样的。你还能调用gc_collect_cycles()函数达到这个目的。他能强制执行周期回收。

  • 相关阅读:
    读《人人都是产品经理》
    前端值得看的博客
    git 常用命令 创建查看删除分支,创建查看删除tag等
    看《如何令选择变得更加容易》
    读【失控】——众愚成智
    html5 postMessage
    下拉滚动加载更多数据
    html select用法总结
    分布式系统事务一致性解决方案
    nginx简易教程
  • 原文地址:https://www.cnblogs.com/lxhyty/p/11308571.html
Copyright © 2020-2023  润新知