PHP 的“未设置”构造如何在内部工作?
Posted
技术标签:
【中文标题】PHP 的“未设置”构造如何在内部工作?【英文标题】:How does PHP's 'unset' construct work internally? 【发布时间】:2014-08-24 19:53:14 【问题描述】:前言:我确实知道“未设置”在用户空间中是如何工作的,但我想了解它在内部是如何工作的。
当在zval structure 上调用 unset 时,它会减少引用计数器 (refcount__gc)。当 refcount__gc 达到 0 时,该变量不再使用,可以删除。问题是它是总是立即完成,还是在某些情况下可以由垃圾收集器稍后完成?
我发现了两个相互矛盾的陈述:
unset() 就像它的名字所说的那样 - 取消设置一个变量。它不会强制立即释放内存。 php 的垃圾收集器将在它认为合适的时候执行它 - 有意尽快,因为无论如何都不需要这些 CPU 周期,或者直到脚本耗尽内存之前,无论首先发生什么。 - *** answer mentioning 2009 php.net documentation
反之:
当 refcount 达到零时,zval 被销毁,它所持有的任何内存现在都是空闲的 - Better Understanding PHP’s Garbage Collection, 2012 article
那么,假设 PHP 5.3 和 PHP 5.5,哪一个是正确的?如果可能的话,也许您可以提供指向 PHP 源代码中未设置定义的链接。谢谢!
【问题讨论】:
【参考方案1】: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 的情况)
但是,如果它不为零,我们将变量标记为稍后由循环垃圾收集器检查。 (第一句话:不一定立即释放)
【讨论】:
感谢您的详细回答,基本上我在寻找递减的引用计数和释放内存逻辑,所以这是您提供的第二个链接。据我了解,这些是lxr.php.net/xref/PHP_5_6/Zend/zend_execute.h#74 中的第 76-80 行,用于检查 refcount == 0,并在 efree_rel(zval_ptr); 中释放内存;对吗?以上是关于PHP 的“未设置”构造如何在内部工作?的主要内容,如果未能解决你的问题,请参考以下文章