是的,平时经常听到大牛说到的gc,就是垃圾回收器,全称Garbage Collection。
早期版本,准确地说是5.3之前(不包括5.3)的垃圾回收机制,是没有专门的垃圾回收器的。只是简单的判断了一下变量的zval的refcount是否为0,是的话就释放否则不释放直至进程结束。
乍一看确实没毛病啊,然而其中隐藏着变量内存溢出的风险:?id=33595 ,无法回收的内存造成了内存泄漏,所以PHP5.3出现了专门负责清理垃圾数据、防止内存泄漏的GC。
下文将由浅入深(凭感觉)来记录下php的垃圾回收机制是怎么一回事?
1.php引用计数基本知识点
2.php的内存管理机制
3.php中垃圾是如何定义的?
4.老版本php中如何产生内存泄漏?
5.5.3版本以后php是如何处理垃圾内存的?
6.涉及到垃圾回收的知识点
php引用计数基本知识点首先必须要先讲讲这个会引起垃圾回收的关键基数是怎么回事?
关于php的zval结构体,以及refcount与is_ref的知识点,在菜鸟学php扩展 之 详解php扩展的变量(四) 已描述非常清楚。
不准确但却通俗的说:
refcount:多少个变量是一样的用了相同的值,这个数值就是多少。
is_ref:bool类型,当refcount大于2的时候,其中一个变量用了地址&的形式进行赋值,好了,它就变成1了。
主要讲讲如何用php来直观的看到这些计数的变化,走一波。
首先需要在php上装上xdebug的扩展。
1.第一步:查看内部结构
<?php $name = "咖啡色的羊驼"; xdebug_debug_zval('name');1
2
3
会得到:
name:(refcount=1, is_ref=0),string '咖啡色的羊驼' (length=18)1
2.第二步:增加一个计数
<?php $name = "咖啡色的羊驼"; $temp_name = $name; xdebug_debug_zval('name');1
2
3
4
会得到:
name:(refcount=2, is_ref=0),string '咖啡色的羊驼' (length=18)1
看到了吧,refcount+1了。
3.第三步:引用赋值
<?php $name = "咖啡色的羊驼"; $temp_name = &$name; xdebug_debug_zval('name');1
2
3
4
会得到:
name:(refcount=2, is_ref=1),string '咖啡色的羊驼' (length=18)1
是的引用赋值会导致zval通过is_ref来标记是否存在引用的情况。
4.第四步:数组型的变量
<?php $name = ['a'=>'咖啡色', 'b'=>'的羊驼']; xdebug_debug_zval('name');1
2
3
会得到:
name: (refcount=1, is_ref=0), array (size=2) 'a' => (refcount=1, is_ref=0),string '咖啡色' (length=9) 'b' => (refcount=1, is_ref=0),string '的羊驼' (length=9)1
2
3
4
5
6
还挺好理解的,对于数组来看是一个整体,对于内部kv来看又是分别独立的整体,各自都维护着一套zval的refount和is_ref。
5.第五步:销毁变量
<?php $name = "咖啡色的羊驼"; $temp_name = $name; xdebug_debug_zval('name'); unset($temp_name); xdebug_debug_zval('name');1
2
3
4
5
6
会得到:
name:(refcount=2, is_ref=0),string '咖啡色的羊驼' (length=18) name:(refcount=1, is_ref=0),string '咖啡色的羊驼' (length=18)1
2
refcount计数减1,说明unset并非一定会释放内存,当有两个变量指向的时候,并非会释放变量占用的内存,只是refcount减1.
php的内存管理机制知道了zval是怎么一回事,接下来看看如何通过php直观看到内存管理的机制是怎么样的。
外在的内存变化先来一段代码:
<?php //获取内存方法,加上true返回实际内存,不加则返回表现内存 var_dump(memory_get_usage()); $name = "咖啡色的羊驼"; var_dump(memory_get_usage()); unset($name); var_dump(memory_get_usage());1
2
3
4
5
6
7
会得到:
int 1593248 int 1593384 int 15932481
2
3
大致过程:定义变量->内存增加->清除变量->内存恢复
潜在的内存变化当执行:
$name = "咖啡色的羊驼";1
时候,内存的分配做了两件事情:1.为变量名分配内存,存入符号表 2.为变量值分配内存