2009-09-16 22 views
112

長時間実行すると、システム上のすべてのメモリが消費される、長時間実行するスクリプトがあります。Pythonメモリリーク

スクリプトの詳細に入るがなければ、私は2つの質問があります。

  1. はフォローする任意の「ベストプラクティス」の発生からの漏れを防ぐことができますされ、ありますか?
  2. Pythonでメモリリークをデバッグするにはどのような方法がありますか?
+3

[このレシピ](http://code.activestate.com/recipes/65333/)が役立っています。 –

+0

便利なデータがあまりにも多く印刷されているようです。 – Casebash

+1

@Casebash:真剣に間違っていることがあれば、それを印刷します。 '__del__'メソッドを持つオブジェクトは、そのサイクル以外は参照されなくなりました。 '__del__'の問題のため、サイクルを壊すことはできません。修理する! –

答えて

4

pythonのメモリリークの "ベストプラクティス"についてはわかりませんが、pythonはガベージコレクタによって自身のメモリをクリアする必要があります。だから、主に私はガベージコレクタによって取り上げられることがないので、いくつかの短い循環リストをチェックすることから始めます。

+3

永遠に保管されています –

+0

永遠に保持されている循環リストやオブジェクトの例を教えてください。 – Daniel

8

グローバルまたは静的なデータ(長い生活データ)を特に見てください。

このデータが無制限に増加すると、Pythonでも問題が発生する可能性があります。

ガベージコレクタはデータを収集することができますが、それ以上は参照されません。しかし、あなたの静的なデータは解放されるべきデータ要素を接続することができます。

もう1つの問題はメモリサイクルになる可能性がありますが、ガベージコレクタは少なくとも理論的にはサイクルを見つけて消滅させる必要があります - 少なくとも長いリビングデータに引っ掛かっていない限り。

長い生きているデータの種類は特に面倒ですか?リストや辞書をよく見てください。何も制限なしに成長することができます。ディクショナリにアクセスすると、辞書のキーの数があなたに大きな目に見えない可能性があります。

3

これは決して徹底的なアドバイスではありません。しかし、将来のメモリリーク(ループ)を避けるという考えで書くときに留意すべき点は、コールバックへの参照を受け入れるものはそのコールバックを弱い参照として格納することです。

13

同様の問題を解決するのに役立つmem_topツール
をお勧めします。

Pythonプログラムでメモリリークの疑いが最も高い瞬間をただちに表示します。

+0

それは本当です...しかし、それは使用方法/結果の説明の方法ではごくわずかです。 –

+0

@me_、このツールには、 "Usage"と "Explaining result"セクションが記録されています。 "refsはオブジェクトからの参照の数です、型はこの型のオブジェクトの数です、バイトはオブジェクトのサイズです"というような説明を追加する必要があります - これを明らかにするのはあまり明白ではないでしょうか? –

+0

ツールの使用方法ドキュメントは、「時から:logging.debug(mem_top())」という1行を返しますが、その結果の説明は著者の実際のエラーです。開発者に正確に何を見ているかを伝えます...私はあなたの答えをノックアウトしていません...それは請求された高レベルの容疑者を示しています...それは完全に使用の結果を理解するための適切なドキュメントを提供していません...たとえば、「結果の説明」出力で、「GearmanJobRequest」が明らかに問題になっていますか?理由についての説明はありません... –

51

私は前述のほとんどのオプションを試してみたが、この小型かつ直感的なパッケージが最善であることが判明:pympler

それは、ガベージコレクションはありませんでしたオブジェクトを追跡することは非常にまっすぐ進むのです、この小さな例チェック:

は、出力はあなたにすべて追加されたオブジェクト、加えて、彼らが消費されるメモリを示しpip install pympler

from pympler.tracker import SummaryTracker 
tracker = SummaryTracker() 

# ... some code you want to investigate ... 

tracker.print_diff() 

経由でパッケージをインストールします。

出力例:

        types | # objects | total size 
====================================== | =========== | ============ 
            list |  1095 | 160.78 KB 
            str |  1093 |  66.33 KB 
            int |   120 |  2.81 KB 
            dict |   3 |  840 B 
     frame (codename: create_summary) |   1 |  560 B 
      frame (codename: print_diff) |   1 |  480 B 

このパッケージには、より多くの機能の数を提供します。 pympler's documentation、特にセクションIdentifying memory leaksをチェックしてください。

+1

面白いこと...私はpymplerを使ってそれを追跡しようとしたとき、私の記憶リークは実際に消えました。おそらくいくつかのガベージコレクションの問題... – sebpiq

+1

'pympler'が** SLOW **になることは注目に値する。半リアルタイムで何かをやっているなら、アプリケーションのパフォーマンスを完全に損なう可能性があります。 –

2

ベストプラクティスについては、再帰関数に注意してください。私の場合は、再帰を伴う問題に遭遇しました(どこにいなくてもかまいません)。私が何をしていたかの簡単な例:

def my_function(): 
    # lots of memory intensive operations 
    # like operating on images or huge dictionaries and lists 
    ..... 
    my_flag = True 
    if my_flag: # restart the function if a certain flag is true 
     my_function() 

def main(): 
    my_function() 

この再帰的に作動するので、メモリ使用量を通じてたびに成長し、成長して、ガベージコレクションをトリガし、機能の遺跡をクリアしません。

私の解決策は、再帰呼び出しをmy_function()から引き出し、main()関数で再呼び出しをいつ行うかです。このようにして関数は自然に終了し、それ自身の後でクリーンアップします。

def my_function(): 
    # lots of memory intensive operations 
    # like operating on images or huge dictionaries and lists 
    ..... 
    my_flag = True 
    ..... 
    return my_flag 

def main(): 
    result = my_function() 
    if result: 
     my_function() 
+4

この方法で再帰を使うことは、Pythonがテールコールを最適化しないため再帰深度の制限に達した場合にも壊れます。デフォルトでは、1000再帰呼び出しです。 –

3

長時間実行されているプロセスのメモリリークを検出して特定するには、次のようにします。運用環境ではstackimpactを使用できるようになりました。下にtracemallocを使用します。詳細はthis postです。

enter image description here

4

Tracemalloc moduleのように統合された内蔵モジュールのPython 3.4から出発し、そしてa third-party libraryは(しかしそれをテストしていない)としてappearently、それはまた、Pythonの以前のバージョンのために利用できます。

このモジュールは、最もメモリを割り当てた正確なファイルと行を出力できます。 IMHOでは、この情報は各タイプの割り当てインスタンスの数よりも無限に価値があります(多くのタプルが時間の99%を占めることになりますが、これは手掛かりですがほとんどの場合ほとんど役に立ちません)。

pyrasiteと組み合わせてtracemallocを使用することをお勧めします。 10回中に9回、top 10 snippetpyrasite-shellで実行すると、10分以内にリークを修正するのに十分な情報とヒントが得られます。しかし、まだ漏れの原因を見つけることができない場合は、pyrasite-shellとこのスレッドで言及されている他のツールとの組み合わせで、おそらくさらにいくつかのヒントが得られます。 pyrasiteが提供する余分なヘルパー(メモリビューアなど)もすべて見てください。