web-dev-qa-db-ja.com

長時間実行されているPerlプログラムでメモリリークを見つけるにはどうすればよいですか?

PerlはGCに参照カウントを使用しており、誤って循環参照を作成するのは非常に簡単です。私のプログラムはますます多くのメモリを使用しているようで、おそらく数日後にオーバーフローするでしょう。

Perlでメモリリークをデバッグする方法はありますか?プログラムにアタッチして、さまざまなタイプのオブジェクトの数を取得することは、良いスタートです。どのオブジェクトが予想よりもはるかに多いかを知っていれば、それらへのすべての参照を確認し、うまくいけばリークを修正できます。

38
taw

Perlneverがそれ自体でシステムにメモリを返すことは適切かもしれません:それはすべてmalloc()とそれに関連するすべてのルール次第です。

malloc()がどのようにメモリを割り当てるかを知ることは、より大きな質問に答えるために重要であり、システムごとに異なりますが、一般に、ほとんどのmalloc()実装は、スタックのような順序でプログラムの割り当てと割り当て解除に最適化されています。 Perlは、メモリの追跡に参照カウントを使用します。つまり、割り当て解除は、(下でmalloc()を使用するGCベースの言語とは異なり)実際には伝えるのはそれほど難しいことではありません割り当て解除が発生する場所と順序。

undef($old_object)を明示的に呼び出すことにより、Cプログラマーがfree(old_object);と言うのと同じように、正しい順序でこの事実を利用するようにプログラムを再編成できる可能性があります。

ロード/コピー/ダンプサイクルが大量にある長時間実行プログラム(日、月など)の場合、exit() and exec()を使用してガベージコレクションを行い、それ以外の場合はデータ構造をパックするだけです。 (Storableを使用)およびファイル記述子($^Fを使用)およびexec($0)-通常は$ENV{EXEC_GC_MODE}のような環境変数が設定されており、同様のものPerlが小さなチャンクをリークしているという理由だけで、独自のリークがない場合でも、システムのmalloc()は返す方法を理解できません。

もちろん、yourコードにリークがある場合は、残りのアドバイスの方が適切です。もともとは このテーマに関する別の質問に 投稿されましたが、明示的に長時間実行されるプログラムをカバーしていませんでした。


すべてのPerlプログラムのメモリリークは、参照を保持するXS、または循環データ構造のいずれかです。 Devel :: Cycle は、ループを含む可能性のある構造がわかっている場合、循環参照を見つけるための優れたツールです。 Devel :: Peek は、予想よりも多い参照カウントを持つオブジェクトを見つけるために使用できます。

他にどこを見ればよいかわからない場合は、 Devel :: LeakTrace :: Fast が最初の場所として適している可能性がありますが、デバッグ用に構築されたPerlが必要です。

リークがXSスペース内にあると思われる場合は、はるかに困難であり、 Valgrind がおそらく最善の策です。 Test :: Valgrind 検索する必要のあるコードの量を減らすのに役立つかもしれませんが、これはWindowsでは機能しないため、Linuxに(少なくともリーク部分を)移植する必要があります。これを行うために。

37
geocar

Devel :: Gladiator は、この分野で役立つもう1つのツールです。

5
Jesse

valgrind は、実行中のコードのメモリリークを特定する優れたLinuxアプリケーションです。 PerlコードがLinuxで実行されている場合は、チェックアウトする必要があります。

3
Yuval F

Cpanモジュールのようです Devel :: Cycle はあなたが探しているものです。コードにいくつかの変更を加える必要がありますが、あまり問題なく参照を見つけるのに役立つはずです。

3
Craig H

他のコメントに加えて、LPW2013での私の Perl Memory Use talk が役立つかもしれません。スライドを説明し、最後にいくつかのかわいいビジュアルといくつかのQ&Aがあるので、 スクリーンキャスト を見ることをお勧めします。

また、Paul Evans Devel :: MAT モジュールを見てみることをお勧めします。

2
Tim Bunce