次のようなものでオブジェクトのサイズを取得していると思います:
sum(sys.getsizeof(i) for i in gc.get_objects())
の結果にgc.get_objects()
は、インタープリター自体によって消費されたメモリは含まれず、ガベージ コレクターによって追跡された Python オブジェクトのみが含まれることに注意してください。また、この関数は、メソッドから正確な結果を返すオブジェクトに依存している__sizeof__()
ため、サードパーティのモジュールを使用している場合、必ずしも正確な結果が期待できるとは限りません。
すでにこれを行っているかもしれませんが、アプリケーションで定期的に呼び出して、コレクターが解放できなかった到達不能オブジェクトがあるかどうかをgc.collect()
確認することができます。gc.garbage
これは、オーバーライドした循環参照を持つクラスがある場合に当てはまります__del__()
( gc の Python ドキュメントを参照してください)。
コードの先頭にこの呼び出しを追加することもお勧めします。
gc.set_debug(gc.DEBUG_UNCOLLECTABLE | gc.DEBUG_INSTANCES | gc.DEBUG_OBJECTS)
stderr
これにより、オブジェクトが循環参照などで見つかるたびにメッセージが出力されます。これにより、どこをより詳しく調べるかについての有用な情報が得られる場合があります。
これまでのところ、この種の問題は objgraph によって検出された可能性がありますが、長期実行デーモンでそれらをアクティブなままにして、そのような問題が発生したときの記録を取得できるため、いずれにしてもそれらを配置する価値があるかもしれません。
C 拡張機能を使用している場合 (自分で作成したものでも、サード パーティ製のものでも)、参照カウントの処理でエラーがないかコードを注意深くチェックしてください。間違いを犯すのはかなり簡単です。また、拡張機能が Python のアロケータの外部に独自のメモリを割り当てるのを止めるものは何もないことに注意してください。この場合、Python インタープリタ内で何をしても、これらのリークが検出されません。
とはいえ、メモリ使用量がまだ単調に増加していて、原因である Python オブジェクトが見つからない場合は、おそらく低レベルの C コードまたは Python インタープリター自体のリークをチェックする時期です。これは優れたツールです。これはValgrindです。
Python で Valgrind を使用するには、Python 抑制ファイルを使用する必要があります。/usr/lib/valgrind/python.supp
これは既にインストールされている場合があります。たとえば、Ubuntu は、このファイルの変更された形式を に配置します。
これを適切に行うには、Python ディストリビューションのREADME.valgrindファイルに記載されているように Python を再コンパイルする必要がありますが、これを行わなくても興味深い結果が得られる場合があります。
Valgrind で Python を実行することについては、このスタック オーバーフローの質問でさらに議論されています。