php 给每个变量都会分配一个叫zval的容器,在这个用其中会存放4个内容:变量类型、变量值、is_ref(判断是否引用)、refcount(只想该变量的个数,用以统计内部引用计数,优化内存)。
可以通过 xdebug_debug_zval()函数检查 is_ref、refcount;
变量被赋值使用,refcount++,使用unset() 删除变量,refcount --;
数组/对象类的复合类型,会多生成一个zval容器(array/object本身),内部的每个变量都会有自己的zval容器;
$a = array('a'); $a[] = &$a; 这时显示
(refcount=1, is_ref=1)=array (
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=1, is_ref=1)=...
) ...代表递归操作,当前数组指向了原来数组
0 => (refcount=1, is_ref=0)='one',
1 => (refcount=1, is_ref=1)=...
) ...代表递归操作,当前数组指向了原来数组
问题来了:当引用计数增加时代表变量正在使用(不在垃圾之中),如果计数减到零,变量容器才会被清除。这时才会产生垃圾周期。在一个垃圾周期中,通过检查引用计数是否减1,且检查变量容器引用次数为0,来发现那部分属于垃圾。这种垃圾会在程序执行结束后会进行清除,但是如果程序一直运行(deamon守护进程模式下)垃圾会一直保存下来不会被清除,这样垃圾越来越多会引起内存泄漏。
解决办法:缓存区内存满了之后需要执行清除程序(主要是多遍历检查,具体功能:模拟删除、模拟回复、真的删除),除了修改配置文件php.ini中配置
zend.enable_gc ,也能通过分别调用
gc_enable() 和
gc_disable()函数来打开和关闭垃圾回收机制。使用
gc_collect_cycles()函数达到这个目的。这个函数将返回使用这个算法回收的周期数。
性能方面:主要有两种因素:内存占用空间的节省,垃圾回收机制执行清理内存的执行时间。