Programmingバックエンド開発者

Pythonにおけるメモリ管理の仕組み、及びガーベジコレクタについて説明してください。循環参照とは何ですか?Pythonはこれにどのように対処していますか?

Hintsage AIアシスタントで面接を突破

回答

Pythonではメモリ管理は自動的に行われます。オブジェクトが作成されるとメモリが割り当てられ、他のオブジェクトがそのオブジェクトを参照しなくなったときにメモリが解放されます。主な戦略は参照カウントです。各オブジェクトには参照カウンタが付随しており、それがゼロになるとオブジェクトは削除されます。

しかし、循環参照が発生する可能性があり、オブジェクトが互いに参照し合い、外部コードからの参照が削除されても参照カウントがゼロにならないことがあります。

これに対処するために、Python(CPython)にはガーベジコレクタ(GC)があり、ルートからアクセスできないオブジェクトのサイクルを検出して削除します。ガーベジコレクタはgcモジュールから制御できます。

サイクルの例:

class Node: def __init__(self): self.ref = None n1 = Node() n2 = Node() n1.ref = n2 n2.ref = n1 del n1, n2 # 循環参照のためオブジェクトはまだ生きています!

騙しの質問

質問:del objを呼び出すと、メモリは常に即座に解放される。これは本当ですか?」

答え: いいえ!del操作はオブジェクトへの1つの参照を削除するだけです。どこかに他の参照(明示的または循環的)が残っている場合、参照カウンタがゼロにならない限りメモリは解放されません。例:

import gc class A: pass x = A() y = x del x # yはまだ参照を持っているので、オブジェクトは生きています! del y # ここでようやくオブジェクトが削除される可能性があります

このテーマの細部を知らなかったために発生した実際のエラーの例


物語

大きなファイルを処理するシステムでは、関連するオブジェクトをメモリに保持していました。外部参照を削除した後でもメモリは解放されませんでした。原因は循環参照で、これがすぐにクリアされず、時にはデストラクタ__del__の存在のために全く清掃されないことがありました。


物語

長寿命のサーバープロセスでは、しばしば循環グラフを持つ大きな一時構造が作成されていました。開発者はGCの一時的なデバッグ出力をオフにしなかったため、稀に発生するが目に見える遅延が横行しました。これは"パフォーマンスの低下"として診断されました。頻繁にガーベジコレクタが実行されることが原因であることが判明しました。


物語

大規模なプロジェクトをPyPy(代替インタープリター)に移植する際、古いコードは参照カウンタによる即時メモリクリーンアップに対するCPythonの特異な動作に依存していましたが、PyPyではオブジェクトが即座には削除されず、GCの"意向"に応じて清掃されるため、ファイルやネットワーク接続のオープン時に予測不可能な動作が発生しました。