5

バックグラウンド

私はツリー構造をしています。このツリー構造内で、ノードの子を二重リンク リストとして維持しています。

ここに画像の説明を入力
(出典:双方向リンクリスト

(このリストを作成する幅優先探索法のために、この構造を選択しました。)

問題

今、私の懸念は、ガベージ コレクターがこのリストを自動的に破棄できるかどうかです。当然、そのような 3 つのルート ノードへの参照のみを保持します。Afaik GC の原則は、メモリ内のデータ構造を収集することであり、そのデータ構造には参照がありません。ただし、二重リンク リストでは、各ノードはその兄弟から参照され、兄弟はノードを参照します。そのため、常にノードへの参照があり、GC はそれを収集しません。

ガベージ コレクターは二重リンク リストを処理しますか?

そうでない場合、それを収集する最も簡単な方法は何ですか?

関連する質問:

Lua が参照カウントの代わりにガベージ コレクターを使用するのはなぜですか?
Python: リストを変更するときのメモリ使用量と最適化

4

1 に答える 1

9

各 Python 実装には、異なるガベージ コレクション スキームがあります。一般的な答えは、「はい、ガベージであれば、ガベージ コレクションを実行する必要があります」です。しかし、おそらくこれよりも具体的なものが必要です。


CPython では、ガベージ コレクションは refcounting とサイクル コレクターを使用します。オブジェクトの refcount が 0 になると、クリーンアップされます。しかし、あなたの場合、リストへのすべての外部参照がなくなると、内部参照がまだ残っているため、参照カウントだけでは問題を解決できません。それがサイクルコレクターの目的です。

__del__ノードにメソッドがなく、「追加のガベージ コレクション」を (直接的または間接的に) 無効にしていないと仮定すると(デフォルトでオンになっています)、サイクル コレクターは、ノードがすべて相互に参照していることを検出しますが、それ以外はそれらを参照していません。 、クリーンアップします。(世代別システムを使用しているため、これには 2 つのパスが必要になる場合があります。)

このモジュールを使用してgc、サイクル コレクター ( gc.collect()) を待機する代わりに明示的に実行したり、その動作を検査したりできます。たとえば、次のようにします。

gc.collect()
oldcounts = gc.get_counts()
del last_reference_to_list
gc.collect()
newcounts = gc.get_counts()
print(oldcounts, newcounts)

… (完全な信頼性ではありませんが、学習とテストの目的には十分です) ノードがすべてなくなったことを確認できるはずです。


ノードにメソッドある場合はどうなりますか? __del__次に、GC に何らかの助けを与える必要があります。あなたがする必要があるのは、__del__メソッドを持つオブジェクトを含むサイクルを壊すことです。リスト間でノードを共有していない場合、これを行うための明白な方法は、リストとdel前後のポインターをたどることです。(技術的には、delどちらか一方のみが必要ですが、両方を行うこともできます。)__del__ノードでメソッドが必要な場合は、おそらくトップレベルdl_list(またはtree_nodeこれらを所有するもの)にメソッドが必要です。そのため、それを配置するのは明らかです。

もちろん、__del__メソッドが必要ない場合は、さらに簡単な解決策があります。それを取り除くだけです。


最後の 1 つの可能性はweakref、後方リンクに使用することですが、前方リンクには通常の参照を使用します。そうすれば、可能なサイクルはありません。ただし、ノードの追加と削除には少し注意して、weakref だけでノードを一時的に離れないようにする必要があります。


Jython または IronPython を使用している場合、ガベージ コレクションは基盤となるランタイム (JVM または .NET) に関連付けられているため、適切なドキュメントを読む必要があります。

PyPy には独自のガベージ コレクター (実際にはさまざまなオプションの選択) があり、こちらについて読むことができます。

あまり一般的でない実装を使用している場合は、同様のドキュメントが利用できるはずです。

于 2013-08-05T22:08:56.080 に答える