PHP GC垃圾回收

PHP GC Garbage Cycle 垃圾回收

基础知识

垃圾:当一个对象没有任何引用指向他的时候就是垃圾(需要释放的内存);也就是当计数器为0的时候,会销毁这个变量,所以这里的垃圾并不能被称为垃圾,这里的垃圾应该是可以成功释放内存,不能被销毁的才是垃圾,和上面需要释放内存的垃圾不是一个意思,要区分开;

定位垃圾的两种算法:

  • reference count 引用计数 计数是0的时候就是垃圾 不能解决循环引用的问题;循环引用会导致内存的泄露;php使用的就是这种算法;php5.3对GC优化,来解决循环引用的问题;
  • root searching 根可达算法,就是从开始找到不是垃圾的,然后删除所有的垃圾,可以解决循环引用的问题;例如java;

优点:自动内存回收编程简单,系统不容易出错误;

引入两个概念:

  • 内存泄漏:程序申请内存后无法释放已经申请的内存;一次内存泄漏并不会产生很大的影响,但是内存的泄漏堆积就会形成内存溢出;
  • 内存溢出:程序申请内存,没有足够的内存供给使用者。

变量容器

  • 看成内存,指向该内存的变量,存放变量数据的地方;
  • 当一个变量被赋值的时候,那么就会生成一个zval的变量容器;
  • 复合类型,array,object类型的变量,会把他们的成员或属性存在自己的符号表,所以一个变量会有多个zval容器;

测试工具:

xdebug_debug_zval()   //好像是需要安装xdebug的插件;
  • refcount : 指向该变量容器的变量数;
  • is_ref : 变量是不是被引用;
  • 注意 上面两个参数的操作对象是变量容器;

php的zval结构体:

struct _zval_struct {  
       /* Variable information */  
       zvalue_value value;     /* value */  
       zend_uint refcount__gc;  //代表一个计数器,表示有多少个变量名指向这个zval变量容器
       zend_uchar type;    /* active type */  
       zend_uchar is_ref__gc;  //此字段是一个布尔值,用来标识变量是否是一个引用,通过这个字段,PHP引擎可以区分一般变量和引用变量
   };  
  • refcount :对象是zval变量容器的变量个数;
  • is_ref:变量是否被引用;
  • 上面的zval也是php弱关系语言的原因;
  • php的变量类型的判断就是依靠type;

zvalue_value的联合体

struct _zval_struct {
    union {
        long lval;
        double dval;
        struct {
            char *val;			//存放的是指针
            int len;          //php直接保存字符串的str,所以strlen的时间复杂度是O(1)
        } str;
        HashTable *ht;               //数组  存放的是地址 指针
        zend_object_value obj;       //对象 php5 这里是一个指针,php3,php4,赋值的时候需要赋值整个对象(copy),所以效率非常低,在php5做了优化,跟随java的步伐,采用了指针或者句柄的形式;
    } value;                    //变量value值
    zend_uint refcount__gc;   //引用计数内存中使用次数,为0删除该变量
    zend_uchar type;           //变量类型
    zend_uchar is_ref__gc;    //区分是否是引用变量
};

弱关系语言和强关系语言

  • 弱关系语言:一个变量可以表示任意的数据类型,不需要声明变量类型;php rust javascript
  • 强关系语言:一个变量被申明为某一个变量类型,在运行过程中,不能把该类型外的值赋给他;java c

写(赋值的意思)时复制 copy

$a = 123;      // 赋值的时候创建一个zval容器变量
$b = $a;		//$b 和 $b指向同一个zval的容器变量  refcount =2
$b = 34;		//$a $b分别指向两个容器变量refcount =1

垃圾回收

php的垃圾回收很简单,就是refcount = 0时候会进行内存回收,也可以手动的unset进行回收;

循环引用的解决方案

什么是循环引用

$a = array('a','b');
$[]=$a;
unset($a);  //会形成一个闭环,造成循环引用;

php5.3之后引入了根缓存机制,来解决循环引用的问题,设定了zval的根缓冲区(默认是1000),当满1000的时候就会对垃圾回收,来解决内存泄漏的问题;

几种可疑垃圾的准则:

  • 计数减少到0,free,肯定不是垃圾;
  • 计数增加也不是垃圾,该容器变量还在用;
  • 只有在计数减少到非零时,才会进入到垃圾周期;(collecting cycle)

在垃圾周期内,通过检查引用计数是否减1,并且检查那些变量容器的引用次数是零,来发现那部分是垃圾;

在这里插入图片描述

紫色看成可疑垃圾;

其实上面的过程简单点说就是:模拟删除一下可疑垃圾,如果引用计数减1,变成0,那么就变成灰色,c代表的是模拟恢复,就是可疑垃圾计数变大于0就要对他恢复,D就是真实的删除;

还有一个很大的误区:因为php有GC,所以不需要手动fclose关闭资源,反正请求结束后php会释放所有的资源,所以没必要去手动关闭;有这样思想的,建议烧书,哈哈哈哈;详细具体看:click

参考书籍 《深入php内核》

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值