PHP's 'unset'在内部构建工作


How does PHP's 'unset' construct work internally?

前言:我知道'unset'是如何在用户区工作的,但我想知道它是如何在内部工作的。

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

我发现了两个相互矛盾的说法:

unset()顾名思义——取消变量的设置。它不会强制立即释放内存。PHP的垃圾收集器将在它认为合适的时候执行此操作——只要不需要那些CPU周期,或者在脚本耗尽内存之前执行,无论先发生什么。- Stackoverflow回答提到2009 php.net文档

,反之:

当recount达到0时,zval被销毁,它所持有的内存现在是空闲的-更好地理解PHP的垃圾收集,2012文章

那么哪个是正确的,比如PHP 5.3和PHP 5.5?如果可能的话,您可以在PHP源代码中提供一个指向unset定义的链接。谢谢你!

TL;DR

两个陈述都为真。

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


循环垃圾收集器

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

在这种情况下,refcount_gc永远不会降为零……在其他地方仍然有一些引用,正常的ZEND_UNSET_*(其中星号是ARRAY, OBJ或VAR)不能取消它。所以它必须等待垃圾回收器。

出于性能原因,只周期性地调用垃圾收集器。

php-src定义

您要求ZEND_UNSET_VAR的定义?4069年http://lxr.php.net/xref/PHP_5_6/Zend/zend_vm_def.h

下面是减少refcount等的主要函数:http://lxr.php.net/xref/PHP_5_6/Zend/zend_execute.h#74

哪个是正确的?

因此,如果refcount为零,我们确定没有任何链接到它,我们可以释放它。(第二个语句:只是在讨论refcount == 0的情况)

但是,如果它不为零,我们将该变量标记为稍后由循环垃圾收集器检查。(第一个语句:不一定立即释放)