3
import weakref
import gc

class MyClass(object):
    def refer_to(self, thing):
        self.refers_to = thing

foo = MyClass()
bar = MyClass()
foo.refer_to(bar)
bar.refer_to(foo)
foo_ref = weakref.ref(foo)
bar_ref = weakref.ref(bar)
del foo
del bar
gc.collect()
print foo_ref()

foo_refとへのbar_ref弱い参照を保持したいのですが、それらが相互に参照している限り、それぞれfoo*ですが、代わりに。を出力します。ガベージコレクターが参照サイクル内に特定のオブジェクトを収集しないようにするにはどうすればよいですか?barNone

barfoo-bar参照サイクルの一部ではなくなったため、このコードではガベージコレクションする必要があります。

baz = MyClass()
baz.refer_to(foo)
foo.refer_to(baz)
gc.collect()

*循環参照がガベージコレクションされるのを防ぐのは無意味に思えるかもしれませんが、私のユースケースではそれが必要です。WebのようWeakValueDictionaryに相互に参照するオブジェクトの束と、束内の各オブジェクトへの弱参照を保持するオブジェクトがあります。孤立している場合、つまり、バンチ内の他のオブジェクトがそのオブジェクトを参照していない場合にのみ、バンチ内のオブジェクトをガベージコレクションする必要があります。

4

1 に答える 1

2

通常、弱参照を使用するということは、オブジェクトがガベージコレクションされるのを防ぐことができないことを意味します。

ただし、参照サイクルの一部のオブジェクトがガベージコレクションされないようにするために使用できるトリックがあります。これらに__del__()メソッドを定義します。

gcモジュールのドキュメントから:

gc.garbage

コレクターが到達不能であることが判明したが解放できなかったオブジェクトのリスト(収集不可能なオブジェクト)。デフォルトでは、このリストには__del__()メソッドを持つオブジェクトのみが含まれます。メソッドがあり、参照サイクルの一部であるオブジェクト __del__()は、必ずしもサイクル内にあるとは限らないが、そこからのみ到達可能なオブジェクトを含め、参照サイクル全体を収集できなくなります。一般に、Pythonが実行する安全な順序を推測することはできないため、Pythonはそのようなサイクルを自動的に収集しません。__del__()メソッド。安全な順序がわかっている場合は、ガベージリストを調べ、リスト内のオブジェクトが原因でサイクルを明示的に中断することで、問題を強制できます。これらのオブジェクトは、ガベージリストに含まれているために存続しているため、ガベージからも削除する必要があることに注意してください。たとえば、サイクルを中断した後del gc.garbage[:]、リストを空にします。一般に、メソッドを使用してオブジェクトを含むサイクルを作成しないことで問題を回避することをお勧めし__del__()ます。その場合、ガベージを調べて、そのようなサイクルが作成されていないことを確認できます。

次のように定義する場合MyClass

class MyClass(object):
    def refer_to(self, thing):
        self.refers_to = thing
    def __del__(self):
        print 'Being deleted now, bye-bye!'

次に、サンプルスクリプトは次のように出力します。

<__main__.MyClass object at 0x108476a50>

.refer_to()ただし、呼び出しの1つをコメントアウトすると、次のようになります。

Being deleted now, bye-bye!
Being deleted now, bye-bye!
None

つまり、メソッドを定義するだけで__del__()、参照サイクルがガベージコレクションされるのを防ぎましたが、孤立したオブジェクトすべて削除されます。

これが機能するためには、循環参照が必要であることに注意してください。参照円の一部ではないオブジェクトグラフ内のオブジェクトは、関係なく選択されます。

于 2012-08-19T12:11:20.360 に答える