15

objgraphを使用して、次のようなオブジェクトの束を見つけました。

インスタンス状態ループ

Python のガベージ コレクターはこのようなサイクルを処理しますか、それともリークしますか?

ループの少し広いビュー:

InstanceState ループのより広い視野

4

4 に答える 4

26

Python の標準参照カウント メカニズムはサイクルを解放できないため、この例の構造はリークします。

ただし、補助的なガベージ コレクション機能はデフォルトで有効になっており、そのコンポーネントのいずれも外部からアクセスできなくなり、メソッドがない__del__()場合は、その構造を解放できるはずです。

その場合、ガベージ コレクター__del__()これらのメソッドを安全に実行する順序を判断できないため、それらを解放しません。

于 2011-11-06T08:19:07.157 に答える
19

フレデリックの答えを少し拡張するために、ドキュメントの「参照カウント」セクションでは、補助サイクルの検出についてうまく説明しています。

物事を説明することは、理解していることを確認する良い方法だと思うので、ここにいくつかの例を示します...これらの2つのクラスでは:

class WithDel(object):
    def __del__(self):
        print "deleting %s object at %s" % (self.__class__.__name__, id(self))


class NoDel(object):
    pass

オブジェクトを作成して参照を失うと、参照カウントのおかげでメソッドaがトリガーされます。__del__

>>> a = WithDel()
>>> a = None  # leaving the WithDel object with no references 
deleting WithDel object at 4299615184

メソッドを使用せず に 2 つのオブジェクト間で参照ループを作成して__del__も、今回はサイクル検出のおかげで、すべてが漏れることはありません。まず、ガベージ コレクションのデバッグ出力を有効にします。

>>> import gc
>>> gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_OBJECTS)

次に、2 つのオブジェクト間で参照ループを作成します。

>>> a = NoDel(); b = NoDel()
>>> a.other = b; b.other = a  # cyclical reference
>>> a = None; b = None # Leave only the reference-cycle
>>> gc.collect()
gc: collectable <NoDel 0x10046ed50>
gc: collectable <NoDel 0x10046ed90>
gc: collectable <dict 0x100376c20>
gc: collectable <dict 0x100376b00>
4
>>> gc.garbage
[]

(これdictはオブジェクトの内部__dict__属性からのものです)

サイクル内のオブジェクトの 1 つでもメソッドが含まれるまで、すべて問題ありません。__del__

>>> a = NoDel(); b = WithDel()
>>> a.other = b; b.other = a
>>> a = None; b = None
>>> gc.collect()
gc: uncollectable <WithDel 0x10046edd0>
gc: uncollectable <dict 0x100376b00>
gc: uncollectable <NoDel 0x10046ed90>
gc: uncollectable <dict 0x100376c20>
4
>>> gc.garbage
[<__main__.WithDel object at 0x10046edd0>]

ポールが述べたように、ループは次のように壊すことができますweakref:

>>> import weakref
>>> a = NoDel(); b = WithDel()
>>> a.other = weakref.ref(b)
>>> b.other = a # could also be a weakref

次に、オブジェクトbへの参照WithDelが失われると、サイクルにもかかわらず削除されます。

>>> b = None
deleting WithDel object at 4299656848
>>> a.other
<weakref at 0x10045b9f0; dead>

ああ、objgraphは、こ​​のような問題のある__del__メソッドを有益に示していたでしょう

于 2011-11-06T14:27:54.040 に答える
5

Python の GC は、すべてのライブ オブジェクトをトラバースして、外部参照なしで参照サイクルを見つけて排除するように設計されています。

gc.get_objectsを実行しgc.collect()てから印刷することで、それが起こっていることを確認できます。gc.garbage

于 2011-11-06T08:17:15.487 に答える
2

親ポインターにweakrefsを使用すると、GCは正常に実行されます。

于 2011-11-06T08:28:21.540 に答える