时间:2021-05-26
当一个PHP线程结束时,当前占用的所有内存空间都会被销毁。那么如果这个线程不结束,怎么回收内存呢?
refcount:引用技术器,可以理解为指向该个容器的指针个数吧。
is_ref:是否被引用(只可能是0或者1)
赋值的流程:
<?php$a = 'aa';xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)$b = $a; //以下的两个其实是一个变量容器xdebug_debug_zval(a); //(refcount=2, is_ref=0),string 'aa' (length=6)xdebug_debug_zval(b); //(refcount=2, is_ref=0),string 'aa' (length=6)unset($b); //对变量容器 refcount 减1xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)xdebug_debug_zval(b); //b: no such symbol b变量被销毁,指向被断掉,如果对应容器的引用技术为零,那么该块儿内存被回收$b = $a;$b = 'bb';xdebug_debug_zval(a); //(refcount=1, is_ref=0),string 'aa' (length=6)xdebug_debug_zval(b); //(refcount=1, is_ref=0),string 'aa' (length=6) 重新申请一个变量容器存储b,a的变量容器引用减1引用的流程:
<?php$a = 'aa';xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)$b = & $a;//变量容器的引用技术加1,引用标记置为1xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string 'aa' (length=2)$b = '123'; //php会发现,该容器变量是引用(is_ref),所以容器变量不用像赋值那样再申请一个xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string '123' (length=2)xdebug_debug_zval('b'); //(refcount=2, is_ref=1),string '123' (length=2)unset($b);//变量容器应用计数减1,引用为零xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string '123' (length=2)xdebug_debug_zval('b'); // b: no such symbol那如果多次引用,unset掉一个,is_ref是否会被置为零,那样bug不就出现了么?变量容器还是引用啊。那么我们来看看:
<?php$a = 'aa';$b = &$a;$c = &$a;//可以看到引用refCount是3,is_ref永远是1xdebug_debug_zval('a'); //(refcount=3, is_ref=1),string 'aa' (length=2)xdebug_debug_zval('b'); //(refcount=3, is_ref=1),string 'aa' (length=2)xdebug_debug_zval('c'); //(refcount=3, is_ref=1),string 'aa' (length=2)unset($b);//我们期待的bug没有出现,只是refcount减1,is_ref还是1xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)xdebug_debug_zval('b'); // b: no such symbolxdebug_debug_zval('c'); //(refcount=2, is_ref=1),string 'aa' (length=2)//那php它怎么知道这个容器还有引用,毕竟is_ref仍然是1,不能计数,那么现在refcount就起作用了,是它告诉php,该变量有几个引用,但问题又来了,如果我干点坏事,在引用的时候,又赋值,它会不会有bug$e = $a;//我们看到期望的bug还是没出现,这时候再赋值,就不像直接赋值那么简单refcount加1了,而是申请了一个新的变量容器xdebug_debug_zval('a'); //(refcount=2, is_ref=1),string 'aa' (length=2)xdebug_debug_zval('e'); //(refcount=1, is_ref=0),string 'aa' (length=2)unset和赋值null都能回收变量么?很多人都错认为,这两个都能回收变量空间,其实错了,null只是把变量占用的空间变小了,从回收上来说,该容器依然存在。
<?php$a = 'aa';$b = $a;$b = null;//又申请了一个变量容器xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)xdebug_debug_zval('b'); //(refcount=1, is_ref=0),null 变量空间并没被回收unset($b);//这时候才释放了b变量容器的空间xdebug_debug_zval('a'); //(refcount=1, is_ref=0),string 'aa' (length=2)xdebug_debug_zval('b'); //b: no such symbol总结
1. 垃圾回收的时机
PHP中,引用计数为0,则内存立刻释放。也就是说,不存在环状引用的变量,离开变量的作用域,内存被立刻释放。环状引用检测则是在满足一定条件下触发,所以在上面的例子中,会看到使用的内存有大幅度的波动。也可以通过 gc_collect_cycles 函数来主动进行环状引用检测。
2. &符号的影响
显式引用一个变量,会增加该内存的引用计数:
$a = "something";
$b = &$a;
此时unset($a), 但是仍有$b指向该内存区域的引用,内存不会释放。
3. unset函数的影响
unset只是断开一个变量到一块内存区域的连接,同时将该内存区域的引用计数-1;在上面的例子中,循环体内部,$a=new A(); unset($a);并不会将$a的引用计数减到零;
4. = null 操作的影响;
$a = null 是直接将$a 指向的数据结构置空,同时将其引用计数归0。
5. 脚本执行结束的影响
脚本执行结束,该脚本中使用的所有内存都会被释放,不论是否有引用环。
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
本文主要讲述运行时类型、对象、线程栈和托管堆之间的相互关系,静态方法、实例方法和虚方法的区别,以及内存的分配和回收。线程栈:在一个进程中可能包含多个线程,一个线
PHP的基本GC概念PHP语言同其他语言一样,具有垃圾回收机制。那么今天我们要为大家讲解的内容就是关于PHP垃圾回收机制的相关问题。希望对大家有所帮助。PHPs
浅谈java内存模型不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。其实java的多线程并发问题最终都会反映在java的内存模型上,所谓线程安
本文实例讲述了php进程(线程)通信基础之SystemV共享内存。分享给大家供大家参考,具体如下:PHP默认情况没有开启功能,要支持该功能在编译PHP的时候要加
内存分配对性能的影响是很大的,分配内存本身需要时间,垃圾回收器回收内存也需要时间,所以应该尽量避免在堆里分配内存。不过直到最近优化HoLacantk时,我才深刻