php中unset变量之后只是断开了变量名和变量内容之间的绑定,变量内容并没有被销毁吗?
下列代码执行结果仍为1
<?php
$a = 1;
$b =& $a;
unset($a);
echo $b;
?>
请问各位大牛,怎么做到真正的清空这段内存?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
要搞懂这个问题,首先要熟悉PHP底层实现中的两个概念:变量类型和符号表。
在PHP的底层实现,也就是zval中,对PHP的变量类型分为了两种实现形式:对于常规类型,数据的值是直接存储在zval中的;对于对象、数组这类复杂的类型,数据的值是剥离zval,存储在内存的其他地方的,而zval中只存储了那块存储数据的内存地址。
符号表是PHP程序中变量名称和zval值对应关系的存储场所,在PHP底层实现中,是使用HashTable实现的。
在我们unset变量时,实际上PHP只是从符号表里标记清除了这个变量的zval。但由于HashTable是直接存储zval而非引用存储的,所以符号表中所占用的zval内存实际上没有真正释放。当然,在某些对符号表的操作中,可能会触发符号表的自我伸缩,这时候才会真正的对内存进行申请和释放。
另外一方面,如果我们unset的是PHP的复杂类型,除了符号表中的zval外,数据的内容实际上存储在另外一块内存中。对于这种引用类型,PHP都会带有一个refcount引用计数,当zval被清除或者其他操作减少了对象的引用时,变量的引用计数会减一。而如果引用计数为零,则表示变量已经不在PHP程序中被使用了。而对于这类变量,PHP的垃圾回收机制会进行回收并释放那一块的内存。
在内存堆栈中,a,b只是指向1的引用。只有把指向1的所有引用都销毁掉,才能真正的将1销毁掉。
output:
对常量来说,到底是引用还是内存值,我们通过下面的方式来验证:
输出如下:
如果是引用存储的话,那么第二个var_dump输出应该是2,2.
你也可以用debug_zval_dump 这个函数来验证。
参考:http://php.net/manual/zh/function.debug-zval-dump.php
这属于底层概念,现代语言大多数都带有垃圾回收机制的。
大多数垃圾回收机制是采用引用计数的来实现的,当你把$a地址引用到$b的时候,这一块内存的引用就会+1。当你在unset($a)的时候代码的引用计数-1。但是并不为0,这代表这块内存还是有别的地方在使用着呢,禁止被回收!
所以在当你没有符号引用$a这段内存的时候,被GC扫描到,这段内存就会被回收了。
不能用c/c++的思想去理解这样的语言,因为很多东西你是不可控的,比如内存管理。
分隔符,如果有新手对楼主的结果有异议的话,可以在线运行一下试试
https://www.bytelang.com/o/s/...
我就贴一下手册 http://php.net/manual/zh/func...