摘要:垃圾回收所谓垃圾就是指通过循环引用自己引用自己,目前只在类型中有出现的形式而导致永远不为。当出现垃圾之后,的引擎有对应的垃圾回收机制。触发这个机制的时机是每次出现减少时候。
自嘲)。。。。。2333,我觉得这是因为在php语言层面就帮我们解决了内存回收的问题,但这让我在和java大牛们吹牛逼的时候,听到什么内存泄露。。。。(纳尼,我tmd怎么从来没遇见过)一脸懵逼。
本人小菜,如果下面所写有什么错误的地方,请大神指出,并且下文,很多都是读书+看源码之后自己的总结。
前言在上一篇中我浅谈的PHP中的基本数据容器,zend_value,zval
实际存储数据的并不全是zend_value,还有一个被zend_value通过指针指向的具体的数据存储结构体,如_zend_array,_zend_string
struct _zend_string { zend_refcounted_h gc; zend_ulong h; /* hash value */ size_t len; char val[1]; };
struct _zend_array { zend_refcounted_h gc; union { struct { ZEND_ENDIAN_LOHI_4( zend_uchar flags, zend_uchar nApplyCount, zend_uchar nIteratorsCount, zend_uchar consistency) } v; uint32_t flags; } u; uint32_t nTableMask; Bucket *arData; uint32_t nNumUsed; uint32_t nNumOfElements; uint32_t nTableSize; uint32_t nInternalPointer; zend_long nNextFreeElement; dtor_func_t pDestructor; };
注意每个结构体中都有一个名为gc的变量,这个变量其实就是 zend_refcounted_h 引用计数
内存回收的两种情况
正常的变量在生命周期完成之后的回收。
这种情况也就是说当zend_value中refCount==0的时候,这时候属于正常的内存回收。
垃圾回收
所谓垃圾: 就是指通过循环引用(自己引用自己,目前只在array,object类型中有出现)的形式而导致refcount永远不为0。这种情况下,如果不处理,但是这些内存无法释放,到时内存泄露
代码如下:
$a = array(1,2 ); xdebug_debug_zval("a"); $a[] = &$a; xdebug_debug_zval("a"); $b=$a; unset($a); xdebug_debug_zval("a"); xdebug_debug_zval("b");
结果如下
a: (refcount=1, is_ref=0) array (size=2) 0 => (refcount=0, is_ref=0)int 1 1 => (refcount=0, is_ref=0)int 2 a: (refcount=2, is_ref=1) array (size=3) 0 => (refcount=0, is_ref=0)int 1 1 => (refcount=0, is_ref=0)int 2 2 => (refcount=2, is_ref=1) &array< a: (refcount=0, is_ref=0)*uninitialized* b: (refcount=2, is_ref=0) array (size=3) 0 => (refcount=0, is_ref=0)int 1 1 => (refcount=0, is_ref=0)int 2 2 => (refcount=1, is_ref=1) &array<
按照正常逻辑,当unset($a),之后,其对应的zeng_value的refCount=1,is_ref=0,但是实际上它却是等于refCount=2,is_ref=0, 这就导致,就算是unset($b),之后,refCount=1,is_ref=0,这种结果,像上面当refCount=0后正常回收内存。
![图片上传中...]
这就是 垃圾。
当出现垃圾之后,php的zend引擎有对应的垃圾回收机制。
其实这种机制的原理就是 :
(1).将这些垃圾放入buffer中。 (2).当buffer到达一定数量之后,启动对所有垃圾的value自身的refCount-1,并将zend_refcounted中的gc_info变量置为GC_GRAY
typedef struct _zend_refcounted_h { uint32_t refcount; /* reference counter 32-bit */ union { struct { ZEND_ENDIAN_LOHI_3( zend_uchar type, zend_uchar flags, /* used for strings & objects */ uint16_t gc_info) /* 就是这个变量 keeps GC root number (or 0) and color */ } v uint32_t type_info; } u; } zend_refcounted_h;
(3).遍历当前buffer,当refCount=0是则表示当前的这个value的确是个垃圾,则将zend_refcounted中的gc_info变量置为GC_WHITE。然后因为所有的value中都减1,所以再次遍历,将那些减一后refcount !=0 的value+1,然后将zend_refcounted中的gc_info变量置为GC_BLACK (4).最后遍历buffer,将buffer中的value的zend_refcounted中的gc_info为GC_WHITE删除 讲完GC垃圾回收算法的原理,貌似我还没有讲在什么时候会触发将这个**可能**的垃圾放入buffer。。。。。。 ***触发这个机制的时机是每次出现refCount减少时候。***
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/28469.html
摘要:所有这些类型,在内部统一用一个叫做的结构表示,在源代码中这个结构名称为。的具体定义在源代码的文件中,下面是相关代码的摘录。 【转】浅谈PHP5中垃圾回收算法(Garbage Collection)的演化 前言 PHP是一门托管型语言,在PHP编程中程序员不需要手工处理内存资源的分配与释放(使用C编写PHP或Zend扩展除外),这就意味着PHP本身实现了垃圾回收机制(Garbage C...
摘要:本书的地址篇收集了一些常见的基础进阶面试题,基础的面试题不再作答。如何实现持久化持久化,将在内存中的的状态保存到硬盘中,相当于备份数据库状态。相当于备份数据库接收到的命令,所有被写入的命令都是以的协议格式来保存的。 本书的 GitHub 地址:https://github.com/todayqq/PH... PHP 篇收集了一些常见的基础、进阶面试题,基础的面试题不再作答。 基础篇 ...
摘要:插入一个元素时先将元素按先后顺序插入数组,位置是,再根据的哈希值映射到散列表中的某个位置,将存入这个位置查找时先在散列表中映射到,得到在数组的位置,再从数组中取出元素。目前只有两种类型会使用这种机制。 1.变量结构 typedef struct _zval_struct zval; typedef union _zend_value { zend_long ...
摘要:本文主要是针对,的话可以移步到庆哥的博客看,还有就是小菜我读的是内核剖析这本书。接下来我会使用到来调试源码本文有参照博客中的部分内容以及代码。 前言 工作+实习快一年了,搞php后端开发,一直很迷茫怎么提高自己,就先从php源码开始吧,本人比较菜,本文章写的比较赶时间,所以有什么错误或者漏掉的地方,望各位大神指正,多交流才能成长嘛,嘿嘿。本文主要是针对php7,php5的话可以移步到庆...
摘要:前言垃圾回收机制在工作中很少碰到,看到阮一峰的书中有写,记录下。垃圾回收机制与垃圾回收机制只考虑对象的强引用垃圾回收机制依赖引用计数,当计数为,则自动回收该对象占用的内存。里面的引用,都不计入垃圾回收机制,所以就不存在这个问题。 showImg(https://segmentfault.com/img/remote/1460000019752744); 前言:垃圾回收机制在工作中很少碰...
阅读 2971·2021-09-22 15:18
阅读 3393·2019-08-30 15:54
阅读 3273·2019-08-30 15:53
阅读 587·2019-08-30 14:12
阅读 813·2019-08-29 17:01
阅读 2197·2019-08-29 14:04
阅读 1377·2019-08-29 13:09
阅读 860·2019-08-26 17:40