PHP的'unset'构造如何在内部工作?

its*_*eee 5 php garbage-collection unset

前言:我确实知道'unset'在userland中是如何工作的,但我想知道它是如何在内部工作的.

当在zval结构上调用unset时,它会减少引用计数器(refcount__gc).当refcount__gc达到0时,该变量不再使用,可以删除.问题是它是否总是立即完成,或者在某些情况下它可以在以后由垃圾收集器完成?

我发现了两个相互矛盾的陈述:

unset()正如它的名字所说 - 取消设置一个变量.它不会强制立即释放内存.PHP的垃圾收集器会在看到拟合时执行它 - 尽快意图,因为无论如何都不需要那些CPU周期,或者在脚本耗尽内存之前,无论先发生什么.- Stackoverflow回答提到2009 php.net文档

相反的是:

当refcount达到零时,zval被销毁,它所持有的任何内存现在都是免费的 - 更好地理解PHP的垃圾收集,2012年文章

那么哪一个是正确的,比如PHP 5.3和PHP 5.5?如果可能,也许您可​​以提供PHP源代码中未设置定义的链接.谢谢!

bwo*_*ebi 5

TL; DR

这两种说法都是对的.

让我解释.(至少从PHP 5.0开始就是这样(以前,我不知道).现在有了phpng,它做了根本性的改变,但是这个原则仍在使用.)


圆形垃圾收集器

循环垃圾收集器仅用于循环引用.当两个对象包含彼此的引用时,我们通常会有它们.

在这种情况下,refcount__gc永远不会降到零......在其他地方仍有一些参考,正常的ZEND_UNSET_*(星号是ARRAY,OBJ或VAR)不能取消它.所以它必须等待垃圾收集器.

并且出于性能原因,仅定期调用垃圾收集器.

php-src定义

你问过ZEND_UNSET_VAR的定义?http://lxr.php.net/xref/PHP_5_6/Zend/zend_vm_def.h#4069

这里是递减引用等的主要功能:http://lxr.php.net/xref/PHP_5_6/Zend/zend_execute.h#74

哪一个是正确的?

因此,如果refcount为零,我们确信没有任何链接到它,我们可以释放它.(第二个陈述:只是在讨论refcount == 0 case)

但是,如果它不为零,我们将变量标记为稍后由循环垃圾收集器检查.(第一声明:未必立即释放)