PHP变量存储在一个zval容器里面的,一个zval变量容器,除了包含变量的类型和值,还包括两个字节的额外信息。
1.变量类型 2. 变量值 3. is_ref 用来标识这个变量是否是属于引用集合 4. refcount 指向该值的变量数量
变量初始化赋值的时候:is_ref为false, refcount为1。
将变量a的值赋给变量b,变量b不会立刻去在内存中存储值,而是先指向变量a的值,一直到变量a有任何操作的时候,因为程序又操作了变量a,所以变量b会自己申请一块内存将值放进去,所以变量a的zval容器中refcount会减1变为1。如果变量c指向a,refcount会加1变为2,is_ref变为true。
当任何关联到某个变量容器的变量离开它的作用域(比如:函数执行结束),或者对变量调用了函数 unset()时,”refcount“就会减1。当“refcount”为0时,这个变量容器就从内存中被删除。
垃圾回收机制
1.在5.2版本或之前版本,PHP会根据refcount值来判断是不是垃圾
如果refcount值为0,PHP会当做垃圾释放掉。
缺点:这种回收机制有缺陷,对于环状引用的变量无法回收。容易造成内存泄漏。
2.在5.3之后版本改进了垃圾回收机制
如果发现一个zval容器中的refcount在增加,说明不是垃圾,
如果发现一个zval容器中的refcount在减少,如果减到了0,直接当做垃圾回收,
如果发现一个zval容器中的refcount在减少,并没有减到0,PHP会把该值放到缓冲区,当做有可能是垃圾的怀疑对象。当缓冲区 达到临界值,PHP会自动调用一个方法取遍历每一个值,如果发现是垃圾就清理。(所有可能根(possible roots 都是zval变量容器),放在根缓冲区(root buffer)中,称为疑似垃圾,同时确保每个可能的垃圾根(possible garbage root)在缓冲区中只出现一次。根缓存区有固定的大小,可存10,000个可能根,当然你可以通过修改PHP源码文件Zend/zend_gc.c中的常量GC_ROOT_BUFFER_MAX_ENTRIES,然后重新编译PHP,来修改这个10,000值。)