私のpythonアプリケーションの1つが、メモリ使用量が着実に増加していると判断してメモリをリークするようです。私の仮説は、これを避けるために最善の努力をしていたにもかかわらず、どこかで循環参照である。問題を特定するために、私は手動で到達不能な項目をチェックする方法を探しています。ツールは純粋にデバッグを目的としています。pythonのgc.garbage(メモリリークのトレース用)
gcモジュールは必要な追跡が可能であると思われ、最後の呼び出し以降に形成された到達不可能な項目のリストをコンパイルすることを目的とした次のコードを試行しました。最初の呼び出しは基本チェックポイントを設定するだけで、到達不能アイテムは識別しません。ここで
def unreachable():
# first time setup
import gc
gc.set_threshold(0) # only manual sweeps
gc.set_debug(gc.DEBUG_SAVEALL) # keep unreachable items as garbage
gc.enable() # start gc if not yet running (is this necessary?)
# operation
if gc.collect() == 0:
return 'no unreachable items'
s = 'unreachable items:\n ' \
+ '\n '.join('[%d] %s' % item for item in enumerate(gc.garbage))
_deep_purge_list(gc.garbage) # remove unreachable items
return s # return unreachable items as text
、_deep_purge_listはサイクルを打破し、手動でオブジェクトを削除することを目指しています。次の実装では、いくつかの一般的なケースを処理しますが、水密ではありません。私の最初の質問はこれに関するものです。
def _deep_purge_list(garbage):
for item in garbage:
if isinstance(item, dict):
item.clear()
if isinstance(item, list):
del item[:]
try:
item.__dict__.clear()
except:
pass
del garbage[:]
非常に制限されたテストに基づいて、セットアップが適切に機能するように見えます。以下の循環参照が正しく一度報告:
class A(object):
def __init__(self):
self.ref = self
print unreachable()
# no unreachable items
A()
print unreachable()
# unreachable items:
# [0] <__main__.A object at 0xb74579ac>
# [1] {'ref': <__main__.A object at 0xb74579ac>}
print unreachable()
# no unreachable items
をただし奇数次何かが起こると:
print unreachable()
# no unreachable items
import numpy
print unreachable()
# unreachable items:
# [0] (<type '_ctypes.Array'>,)
# [1] {'__module__': 'numpy.ctypeslib', '__dict__': <attribute '__dict__' of 'c_long_Array_1' objects>, '__weakref__': <attribute '__weakref__' of 'c_long_Array_1' objects>, '_length_': 1, '_type_': <class 'ctypes.c_long'>, '__doc__': None}
# [2] <class 'numpy.ctypeslib.c_long_Array_1'>
# [3] <attribute '__dict__' of 'c_long_Array_1' objects>
# [4] <attribute '__weakref__' of 'c_long_Array_1' objects>
# [5] (<class 'numpy.ctypeslib.c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)
print unreachable()
# unreachable items:
# [0] (<type '_ctypes.Array'>,)
# [1] {}
# [2] <class 'c_long_Array_1'>
# [3] (<class 'c_long_Array_1'>, <type '_ctypes.Array'>, <type '_ctypes._CData'>, <type 'object'>)
繰り返し呼び出しは、その最後の結果を返し続けます。この問題は、インポート後に初めて到達不能が呼び出されたときには発生しません。しかし、この時点では、私はこの問題が気にしないと信じる理由はありません。私の推測では、それは私のアプローチの欠陥を明らかにする。
私の質問:
- はgc.garbage内の項目を削除する良い方法はありますか?理想的には、 は、gcにそれらを削除する方法です(そうすべきですか?) DEBUG_SAVEALLを使わないで済みますか?
- 誰でもnumpyのインポートに関する問題を説明することができますか? は問題を解決する方法を提案できますか?
付け足し:
それがコードは以下の意図に近い行うように見える:GCによって提供されるよう
def unreachable():
import gc
gc.set_threshold(0)
gc.set_debug(gc.DEBUG_LEAK)
gc.enable()
print 'collecting {{{'
gc.collect()
print '}}} done'
しかし、デバッグのためにI型/ IDオーバーリッチ文字列表現を好みます。さらに、以前のアプローチの欠陥を理解し、gcモジュールについて何かを学びたいと思います。あなたの助けを鑑賞
、
Gertjan
更新06/05:
地元の人々()は、直前に呼び出された場合を除き、私は、最初の実装は、任意の到達不能項目を報告しなかった事態に遭遇しました戻り値を破棄します。これがgcのオブジェクト追跡にどのように影響するかを理解していないと、私はさらに混乱します。私はこの問題を示す小さな例を作るのがどれくらい簡単かはわかりませんが、要求があればそれを撃つことができます。
私はこれをスキミングしましたが、 'gc.DEBUG_SAVEALL'を誤解しているかもしれません。解放されたオブジェクトを' gc.garbage'に(単に解放するのではなく)追加するためのものです。 – blueyed