引用计数:
每一个变量都有zval容器存储,如
<?
$a= "new string";
?>
可以用xdebug_debug_zval('a'); 这样去查询当前引用的情况,其中会有两个值;
a: (refcount=1, is_ref=0)='new string'
refcount 代表有几个变量在使用这个容器,也就是引用计数;
is_ref代表 自定义的引用生成,没有的话就是0,也就是false
以前的php版本所引用的计数内存机制,无法处理循环引用内存泄露问题。
回收周期:
一个变量的引用计数在持续增加(refcount),就说明这个变量还在持续使用,但是如果引用计数减少到0,所在变量容器将被清除。即,当refcount非0的时候,才会是一个垃圾周期。在这一个垃圾周期中,通过检查引用次数是否减1,并且哪些变量容器引用次数是0,来发现垃圾。
为避免检查所有的引用计数减少的垃圾,这个回收算法把所有可能是垃圾的,放到缓冲区,是疑似垃圾;确保每个垃圾在缓冲区只出现一次,仅仅在根缓冲区满了的时候,才对所有不同的变量容器进行垃圾回收操作。
默认的php垃圾回收都是打开的,php.ini文件中,有一个zend.enable_gc参数,可以修改;
根缓存区有固定的大小,可存10,000个可能根
可以通过修改PHP源码文件Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新编译PHP,来修改这个10,000值
如果垃圾回收机制关闭,那么会有很多的可能根,存在于缓冲区,如果是循环引用的一部分,那么永远不会被清除,最终会导致内存泄漏。(内存泄漏时指申请的内存无法释放;无法释放的内存多了,堆积在一起叫内存溢出)。
除了修改配置zend.enable_gc,也能通过分别调用gc_enable() 和 gc_disable()函数来打开和关闭垃圾回收机制。调用这些函数,与修改配置项来打开或关闭垃圾回收机制的效果是一样的。即使在可能根缓冲区还没满时,也能强制执行周期回收。你能调用gc_collect_cycles()函数达到这个目的。这个函数将返回使用这个算法回收的周期数。
因为一些可能根也许存不进有限的根缓冲区。因此,就在你调用gc_disable()函数释放内存之前,先调用gc_collect_cycles()函数可能比较明智
网友评论