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

簡単な答えは、これら 2 つのオブジェクトを解放する必要があるということです。

そうでない場合、これはバグと見なされるべきです。

テストするには: デストラクタを持つクラスを作成し、それが呼び出されることを確認します。

于 2013-01-08T22:06:02.453 に答える
1

要するに:いいえ。

つまり$storage、このオブジェクトへの参照がもうないことを意味します。次にガベージ コレクターが実行されると、このオブジェクトがクリーンアップされ、参照元のすべてのオブジェクト$storageの refCount が 1 減少します。まったく同じことが起こります: 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 バグ #63917 [1] で強調されているように見える反復の問題は、実際には唯一のバグのある問題だと思います。最初に、destruct-with-attachments シナリオのバグを疑うようになりました。

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

于 2013-01-09T16:16:06.477 に答える