1

__destruct外部オブジェクトがスコープから外れるとすぐに循環参照がクリーンアップされるように、クラスのを設定する方法を思い出しているようです。しかし、私が作成した簡単なテストは、これが私が期待/期待したように動作していないことを示しているようです。

最も外側のオブジェクトがスコープから外れたときにPHPがクラスを正しくクリーンアップするようにクラスを設定する方法はありますか?

私はこのコードを書くための別の方法を探していません、私はこれができるかどうかを探しています、もしそうなら、どのように?私は通常、可能な限りこれらのタイプの循環参照を避けようとします。

class Bar {
    private $foo;
    public function __construct($foo) {
        $this->foo = $foo;
    }
    public function __destruct() {
        print "[destroying bar]\n";
        unset($this->foo);
    }
}

class Foo {
    private $bar;
    public function __construct() {
        $this->bar = new Bar($this);
    }
    public function __destruct() {
        print "[destroying foo]\n";
        unset($this->bar);
    }
}

function testGarbageCollection() {
    $foo = new Foo();
}

for ( $i = 0; $i < 25; $i++ ) {
    echo memory_get_usage() . "\n";
    testGarbageCollection();
}

出力は次のようになります。

60440
61504
62036
62564
63092
63620
 [ destroying foo ]
 [ destroying bar ]
 [ destroying foo ]
 [ destroying bar ]
 [ destroying foo ]
 [ destroying bar ]
 [ destroying foo ]
 [ destroying bar ]
 [ destroying foo ]
 [ destroying bar ]

私が望んでいたこと:

60440
 [ destorying foo ]
 [ destorying bar ]
60440
 [ destorying foo ]
 [ destorying bar ]
60440
 [ destorying foo ]
 [ destorying bar ]
60440
 [ destorying foo ]
 [ destorying bar ]
60440
 [ destorying foo ]
 [ destorying bar ]
60440
 [ destorying foo ]
 [ destorying bar ]

アップデート:

PHP> 5.3に関連するこの質問に対するいくつかの優れた回答がありますが、実際には私のプロジェクト(PHP 5.2.x)に関連しているため、PHP<5.3で機能する回答を選択しました。

4

4 に答える 4

3

解決策は、PHP >= 5.3 では、マニュアルのガベージ コレクションセクションで説明されている内容を使用することです。

特に、gc_* 関数は興味深いものになる可能性がありgc_collect_cyclesます。とりわけ、「 」を参照してください。


PHP >= 5.3 を使用して、投稿したコードの一部の場合:

  • ガベージコレクションが機能するはずです
  • ただし、 PHPが必要と判断した場合にのみ実行されます

2 番目の点は非常に重要です。コードが短いため、多くのメモリは必要ありません。これは、ループの各反復の最後にガベージ コレクションが実行されないことを意味します。

  • OK、これでメモリが少し解放されます
  • とにかく十分なメモリが残っているので、それは必要ありません

また、ガベージ コレクションには時間がかかるため、PHP はそれほど頻繁には実行しません。


しばらく前にブログに記事を書き、そこでいくつかのテストを行いました。フランス語ですが、このセクションのグラフ(ここでは言語の壁はありません)は、必要に応じてガベージ コレクターが時々実行されることを明確に示しています。

于 2010-03-23T07:45:35.183 に答える
2

__destructオブジェクトが再利用されるときにのみ呼び出されるため、そのために使用することはできません。ただし、手動のクリーンアップ関数を作成できます。

class Foo {
  private $bar;
  public function __construct() {
    $this->bar = new Bar($this);
  }
  public function cleanup() {
    $this->bar = null;
  }
  public function __destruct() {
    print "[destroying foo]\n";
  }
}

class Bar {
  private $foo;
  public function __construct($foo) {
    $this->foo = $foo;
  }
  public function __destruct() {
    print "[destroying bar]\n";
  }
}

function testGarbageCollection() {
  $foo = new Foo();
  $foo->cleanup();
}

これがどれほど役立つかはわかりませんが、実際にはそれが唯一のオプションです < 5.3

于 2010-03-23T10:40:44.763 に答える
2

http://docs.php.net/features.gc.collecting-cycles :

ガベージ コレクタをオンにすると、ルート バッファがいっぱいになるたびに、上記のサイクル検出アルゴリズムが実行されます。ルート バッファのサイズは 10,000 個のルートに固定されています (ただし、PHP ソース コードの Zend/zend_gc.c で GC_ROOT_BUFFER_MAX_ENTRIES 定数を変更し、PHP を再コンパイルすることでこれを変更できます)。ガベージ コレクタをオフにすると、サイクル検出アルゴリズムは実行されません。ただし、この構成設定でガベージ コレクション メカニズムがアクティブ化されているかどうかに関係なく、可能性のあるルートは常にルート バッファーに記録されます。

http://docs.php.net/features.gc.performance-considerations :

まず第一に、ガベージ コレクション メカニズムを実装する全体的な理由は、前提条件が満たされるとすぐに循環参照変数をクリーンアップすることによってメモリ使用量を削減することです。PHP の実装では、これはルート バッファがいっぱいになるか、関数gc_collect_cycles()が呼び出されるとすぐに発生します。
于 2010-03-23T07:46:24.713 に答える
0

5.3以降、次のことができます

于 2010-03-23T07:45:26.193 に答える