7

特にデストラクタが呼び出されたときのCPythonガベージコレクタの内部を理解しようとしています。これまでのところ、動作は直感的ですが、次の場合は私をつまずかせます。

  1. GCを無効にします。
  2. オブジェクトを作成してから、そのオブジェクトへの参照を削除します。
  3. オブジェクトが破棄され、_____del_____メソッドが呼び出されます。

これは、ガベージコレクターが有効になっている場合にのみ発生すると思いました。誰かがこれが起こる理由を説明できますか?デストラクタの呼び出しを延期する方法はありますか?

import gc
import unittest

_destroyed = False

class MyClass(object):

    def __del__(self):
        global _destroyed
        _destroyed = True

class GarbageCollectionTest(unittest.TestCase):

    def testExplicitGarbageCollection(self):
        gc.disable()
        ref = MyClass()
        ref = None
        # The next test fails. 
        # The object is automatically destroyed even with the collector turned off.
        self.assertFalse(_destroyed) 
        gc.collect()
        self.assertTrue(_destroyed)

if __name__=='__main__':
    unittest.main()

免責事項:このコードは本番用ではありません-これは非常に実装固有であり、Jythonでは機能しないことはすでに説明しました。

4

3 に答える 3

11

Pythonには、参照カウントのガベージコレクションと循環gcガベージコレクションの両方があり、モジュールが制御するのは後者です。参照カウントを無効にすることはできないため、サイクリックガベージコレクターがオフになっている場合でも発生します。

の後にオブジェクトへの参照が残っていないためref = None、その__del__メソッドは、参照カウントがゼロになった結果として呼び出されます。

ドキュメントには手がかりがあります:「コレクターはPythonですでに使用されている参照カウントを補足するので...」(私の強調)。

オブジェクトがそれ自体を参照するようにすることで、最初のアサーションの起動を停止できます。これにより、たとえば、次のコンストラクターをオブジェクトに与えることで、その参照カウントがゼロになりません。

def __init__(self):
    self.myself = self

しかし、そうすると、2番目のアサーションが起動します。これは、メソッドを使用したガベージサイクル__del__が収集されないためです。gc.garbageのドキュメントを参照してください。

于 2010-04-05T11:31:07.500 に答える
5

ここのドキュメント(元のリンクはPython 3.5までがここにあり、後で再配置されたドキュメントセクションへのリンクでした)は、「オプションのガベージコレクタ」と呼ばれるものが実際に循環ガベージのコレクタである方法を説明しています(参照カウントではない種類)キャッチ)(ここも参照)。ここでは、サイクリックとの相互作用に賛成して、参照カウントについて説明しgcます。

Pythonは従来の参照カウントの実装を使用しますが、参照サイクルを検出するために機能するサイクル検出器も提供します。これにより、アプリケーションは直接または間接の循環参照の作成について心配する必要がなくなります。これらは、参照カウントのみを使用して実装されたガベージコレクションの弱点です。参照サイクルは、それ自体への(場合によっては間接的な)参照を含むオブジェクトで構成されているため、サイクル内の各オブジェクトの参照カウントはゼロ以外です。通常の参照カウントの実装では、サイクル自体への参照がそれ以上ない場合でも、参照サイクル内のオブジェクトに属するメモリ、またはサイクル内のオブジェクトから参照されるメモリを再利用することはできません。

于 2010-04-05T14:11:59.753 に答える
4

ガベージコレクターの定義に応じて、CPythonには2つのガベージコレクターがあります。1つは参照カウントで、もう1つは参照カウントです。
参照カウンターは常に機能しており、システムの実行時間に大きな影響を与えない非常に高速で軽量なため、オフにすることはできません。
もう1つ(マークアンドスイープのいくつかのバリエーション)は、頻繁に実行され、無効にすることができます。これは、実行中にインタプリタを一時停止する必要があるためです。これは、間違ったタイミングで発生し、かなりのCPU時間を消費する可能性があります。
それを無効にするこの機能は、タイムクリティカルなことをすることを期待しているときにあり、このGCがなくても問題は発生しません。

于 2010-04-05T11:38:38.180 に答える