如果 SplObjectStorage 实例在仍然附加了某些对象的情况下进行了破坏,它是否会先隐式分离对象,或者通过 SplObjectStorage 的引用来导致内存泄漏那些悬垂物体?我正在尝试确定用户区代码是否“在破坏之前分离任何剩余的东西”是必要的,以防止这样的内存泄漏。
$storage = new SplObjectStorage();
$x = new stdClass();
$y = new stdClass();
$storage->attach($x);
$storage->attach($y);
$storage = null;
// did not explicitly detach $x and $y... does $storage's destruction do it?
// or do the zval counts on $x and $y now off by one?
$x = null;
$y = null;
// at this point, are there two dangling references to $x and $y,
// simply because $storage did not dereference from them before destroying itself?
答案 0 :(得分:1)
简单的答案是:它应该释放这两个对象。
如果不是这种情况,则应视为错误。
测试:使用析构函数创建一个类,并确保它被调用。
答案 1 :(得分:1)
简而言之:否。
In Long:当$storage
被解除引用时,它的所谓“refCount”为零,这意味着不再有对这个对象的引用。现在,下一次垃圾收集器运行时,它将清理此对象,并且从$storage
引用的每个对象都会将其refCount减少一个。现在完全相同:GC注意到,没有任何内容,引用了对象并将释放它们(通常在相同的垃圾收集器周期中,因为为什么不呢?)
答案 2 :(得分:0)
如果此测试结构正确,则似乎表明在销毁存储之前分离项目与仍然附加项目时存储的销毁相比没有明显差异。注释掉detach()块不会导致check()输出中的任何可见变化。
<?php
class MyStorage extends SplObjectStorage
{
public function __destruct()
{
echo "__destruct() of ";
var_dump($this);
//parent::__destruct(); // there is no SplObjectStorage::__destruct()
}
}
class Foo
{
public function __destruct()
{
echo "__destruct() of ";
var_dump($this);
}
}
function check($message)
{
global $storage, $x, $y, $z;
echo $message, ':', PHP_EOL;
echo '$storage: ', xdebug_debug_zval('storage');
echo '$x : ', xdebug_debug_zval('x');
echo '$y : ', xdebug_debug_zval('y');
echo '$z : ', xdebug_debug_zval('z');
echo PHP_EOL, PHP_EOL;
}
check("Starting environment");
$storage = new MyStorage();
check("\$storage created");
$x = new Foo();
check("\$x created");
$y = new Foo();
check("\$y created");
$z = new Foo();
check("\$z created");
$storage->attach($x);
$storage->attach($y);
$storage->attach($z);
check("Everything is attached");
// comment out this detach() block for comparison testing
$storage->detach($x);
$storage->detach($y);
$storage->detach($z);
check("Everything is detached");
// the check() output here is key for comparing with the final check() output below
$storage = null;
check("$storage destructed");
$x = null;
check("$x destructed");
$y = null;
check("$y destructed");
$z = null;
check("$z destructed");
// final check() output appears here
我认为当我在我的类中使用SplObjectStorage对象编写显式userland detach()步骤时,我的自我混淆就被创建了。我认为PHP Bug#63917 [1]似乎突出显示的迭代问题实际上是唯一的错误问题,它首先让我怀疑与附件销毁方案存在错误。