5

如果一个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?
4

3 回答 3

1

简单的答案是:它应该释放这两个对象。

如果不是这种情况,则应将其视为错误。

测试:创建一个带有析构函数的类,并确保它被调用。

于 2013-01-08T22:06:02.453 回答
1

简而言之:没有。

在 Long:$storage被取消引用的那一刻,它有一个所谓的“refCount”为零,这意味着不再有对该对象的引用。现在,下次垃圾收集器运行时,它将清理该对象,并且从中引用的每个对象$storage都将其 refCount 减一。现在发生了完全相同的情况:GC 注意到,没有任何东西引用对象并将释放它们(通常在同一个垃圾收集器周期内,因为为什么不呢?)

于 2013-01-08T22:06:25.010 回答
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 对象的类中编写显式用户区 detach() 步骤时,造成了我的自我困惑。我认为 PHP Bug #63917 [1] 似乎突出的迭代问题实际上是唯一的错误问题,这首先让我怀疑带有 destruct-with-attachments 场景的错误。

[1] -- http://bugs.php.net/bug.php?id=63917

于 2013-01-09T16:16:06.477 回答