PHP5.3以前 引用计数机制
PHP5.3之前使用过内存回收算法Reference Counting 引用计数。
其思想是,为内存对象分配一个计数器,当内存对象建立时计数器初始化为1。(如$a = "hello world"
)
以后每一个新变量引用该变量,(如赋值$a = $b
),计数器加1;当减少引用次内存对象(unset($a)
),计数器减1。
把一个变量赋值给另一变量将增加引用次数(refcount)
1 |
|
当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束),或对变量调用了函数 unset()时,refcount
就会减1
1 |
|
缺点
引用计数虽然简单,但是会有一个致命的缺陷,在循环引用的时候会造成内存泄露
1 |
|
因为 refcount = 1
不等于 0,所以它不会被当作垃圾回收。但同时在符号表中找不到哪个符号指向这个 zval,导致用户也没有办法手动清除。最终的结果就是在这个脚本结束之前,这个结构会一直占用内存,导致内存泄漏。
PHP5.3以后 回收周期
算法思想:深搜遍历
1.把所有可能根(possible roots或者疑似垃圾,都是zval变量容器),放在**根缓冲区(root buffer)中(这样可以同时确保每个可能的垃圾根(possible garbage root)**在缓冲区中只出现一次),仅仅在根缓冲区满了时,才对缓冲区内部所有不同的变量容器执行垃圾回收操作。
2.模拟删除根缓冲区的疑似垃圾,每个变量只能被模拟删除一次。模拟删除时可能将不是疑似垃圾的普通变量引用数减”1”,如果某个普通变量引用计数变成0了,就对这个普通变量再做一次模拟删除。
3.模拟恢复疑似垃圾。恢复的条件是,当变量的引用计数大于0时才对其做模拟恢复。同样每个变量只能恢复一次。这样剩下的一堆没能恢复的就是该删除的节点了,在步下一步中遍历出来真的删除掉。
PHP5.3算法特性:
并不是每一次refcount减少都进入回收周期,当根缓冲区满了才开始垃圾回收