AI智能
改变未来

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内核》

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » PHP GC垃圾回收