Python の __del__ マジック メソッドは、オブジェクトのターミネータとも呼ばれ、オブジェクトがメモリから削除される直前に呼び出されるメソッドです。実際にはメモリからオブジェクトを削除する仕事はしません。それがどのように起こるかは後で説明します。代わりに、このメソッドは、オブジェクトが削除される前に必要なクリーンアップを実行するために使用されます。たとえば、オブジェクトの作成時に開いていたファイルをすべて閉じます。
このセクションでは、例として次のクラスを使用します。
class MyNameClass: def __init__(self, name): self.name = name def __del__(self): print(f"Deleting {self.name}!")
上記の例では、初期化時に入力として名前を受け入れるクラスを定義しており、ファイナライザーが呼び出されると、関連するインスタンスの名前を出力して通知します。こうすることで、どのオブジェクトがいつメモリから削除されたかを知ることができます。
それでは、CPython はいつメモリからオブジェクトを削除することを決定するのでしょうか?これを行う方法は 2 つあります (CPython 3.10 時点では)。参照カウントとガベージ コレクションです。
Python でオブジェクトへのポインターがある場合、それはオブジェクトへの参照です。特定のオブジェクト a について、CPython は、 a を指す他のものがいくつあるかを追跡します。このカウンタがゼロに達した場合、他にオブジェクトが使用されていないため、オブジェクトをメモリから安全に削除できます。例を見てみましょう。
>>> Harward = MyNameClass("Harward") >>> del Harward Deleting Harward! >>>
ここでは、新しいオブジェクト (MyNamedClass("Harward")) を作成し、それへのポインター (Harward =) を作成します。次に、Harwade を削除すると、この参照も削除され、MyNamedClass インスタンスの参照カウントは 0 になります。したがって、CPython はメモリからそれを削除することを決定します。そして、その直前に、その __del__ メソッドが呼び出され、上で見たメッセージが出力されます。
オブジェクトに対して複数の参照を作成した場合、オブジェクトを削除するにはすべての参照を削除する必要があります。
>>> bob = MyNameClass("Bob") >>> bob_two = bob # creating a new pointer to the same object >>> del bob # this doesn't cause the object to be removed... >>> del bob_two # ... but this does Deleting Bob!
もちろん、MyNamedClass インスタンス自体にポインターを含めることができます。結局のところ、これらは任意の Python オブジェクトであり、任意のプロパティを追加できます。例を見てみましょう。
>>> jane = MyNamedClass("Jane") >>> bob = MyNamedClass("Bob") >>> jane.friend = bob # now the "Jane" object contains a pointer to the "Bob" object... >>> bob.friend = jane
上記のコード スニペットで行ったことは、いくつかの循環参照を設定することです。 Jane という名前のオブジェクトには Bob という名前のオブジェクトへのポインタが含まれており、その逆も同様です。次のことを行うと、事態は面白くなります。
>>> del jane >>> del bob
これで、名前空間からオブジェクトへのポインターが削除されました。現在、これらの MyNameClass オブジェクトにはまったくアクセスできませんが、それらが削除されようとしていることを示す印刷メッセージは表示されません。これは、これらのオブジェクトが相互に含まれる参照をまだ持っているため、その参照カウントが 0 ではないためです。
ここで作成するのはループ分離です。この構造では、各オブジェクトはループ内に少なくとも 1 つの参照を持ち、それを存続させますが、ループ内のすべてのオブジェクトをアクセスした名前空間から削除することはできません。
次に、ループ分離を作成したときの直感的なパフォーマンスを示します。
まず、2 つのオブジェクトを作成します。各オブジェクトには名前空間内に名前があります。
次に、各オブジェクトにポインターを追加して 2 つのオブジェクトを接続します。
#最後に、両方のオブジェクトの元の名前を削除して、名前空間からポインターを削除します。この時点では、2 つのオブジェクトには名前空間からアクセスできませんが、各オブジェクトにはもう一方のオブジェクトへのポインターが含まれているため、それらの参照カウントはゼロではありません。
したがって、ランタイムの作業メモリから無駄なリサイクル不可能なオブジェクトを排除するには、参照カウントだけでは不十分であることは明らかです。ここで CPython のガベージ コレクターが登場します。
以上がPython ガベージ コレクション メカニズムでの参照カウントの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。