Github: https://github.com/pythonprofilers/memory_profiler
メモリプロファイラ
これは、プロセスのメモリ消費量と、Pythonプログラムのメモリ消費量の行単位の分析を監視するためのPythonモジュールです。 これはpsutilモジュールに依存する純粋なpythonモジュールです。
インストール
easy_installまたはpip経由でインストールするには:
$ easy_install -U memory_profiler # pip install -U memory_profiler
ソースからインストールするには、パッケージをダウンロードし、以下のように入力します。
$ python setup.py install
使用法
行ごとのメモリ使用量
line-by-lineメモリ使用モードは、 line_profilerと同じように使用されます。まず、 @ profileで@profile
する機能を装飾してから、特殊なスクリプトでスクリプトを実行します(この場合、 Pythonインタプリタ)。
次の例では、リストa
、 b
を割り当てa
からb
を削除する単純な関数my_func
を作成します。
@profile def my_func(): a = [1] * (10 ** 6) b = [2] * (2 * 10 ** 7) del b return a if __name__ == '__main__': my_func()
コードを実行して、 -m memory_profiler
オプションをpythonインタプリタに渡して、memory_profilerモジュールをロードし、行ごとの解析をstdoutに出力します。 ファイル名がexample.pyの場合は、次のようになります。
$ python -m memory_profiler example.py
出力は次のようになります。
Line # Mem usage Increment Line Contents ============================================== 3 @profile 4 5.97 MB 0.00 MB def my_func(): 5 13.61 MB 7.64 MB a = [1] * (10 ** 6) 6 166.20 MB 152.59 MB b = [2] * (2 * 10 ** 7) 7 13.61 MB -152.59 MB del b 8 13.61 MB 0.00 MB return a
最初の列は、プロファイリングされたコードの行番号を表し、2番目の列( Mem usage )は、その行が実行された後のPythonインタプリタのメモリ使用量を表します。 3番目の列( インクリメント )は、現在の行の最後の行との差を表します。 最後の列( 行目次 )は、プロファイルされたコードを出力します。
デコレータ
関数デコレータも利用できます。 次のように使用します。
from memory_profiler import profile @profile def my_func(): a = [1] * (10 ** 6) b = [2] * (2 * 10 ** 7) del b return a
この場合、コマンドラインで-m memory_profiler
を指定せずにスクリプトを実行することができます。
関数デコレータでは、デコレータ関数の引数として精度を指定できます。 次のように使用します。
from memory_profiler import profile @profile(precision=4) def my_func(): a = [1] * (10 ** 6) b = [2] * (2 * 10 ** 7) del b return a
コマンドラインで-m memory_profiler
を使用してデコレータ@profile
持つPythonスクリプトが呼び出された場合、 precision
パラメータは無視されます。
時間ベースのメモリ使用量
場合によっては、外部プロセス(Pythonスクリプトであろうとなかろうと)の(行単位ではなく)時間の関数として、完全なメモリ使用量レポートを持つことが有用な場合もあります。 この場合、実行可能なmprof
が役に立ちます。 次のように使用します。
mprof run <executable> mprof plot
最初の行は実行可能ファイルを実行し、現在のディレクトリに書き込まれたファイルに時間とともにメモリ使用量を記録します。 それが終わったら、2行目を使ってグラフプロットを得ることができます。 記録されたファイルにはタイムスタンプが含まれており、複数のプロファイルを同時に保持することができます。
各mprofサブコマンドのヘルプは、-hフラグ(例:mprof run -h)で取得できます。
Pythonスクリプトの場合、前のコマンドを使用しても、指定された時間に実行される関数に関する情報はありません。 ケースによっては、メモリ使用量が最も高いコード部分を特定することが難しい場合があります。
関数にプロファイルデコレータを追加してPythonスクリプトを実行する
mprof run <script>
プロファイリングされた機能を開始/終了するときにタイムスタンプを記録します。 ランニング
mprofプロット
後で結果をプロットし、プロット(matplotlibを使用)を次のようにします。
これらの機能については、 ここで説明します 。
警告
Pythonファイルがmemory_profilerインポートプロファイルからメモリプロファイラをインポートする場合、これらのタイムスタンプは記録されません。 インポートをコメントアウトし、機能を装飾したままにして、再実行します。
mprofで使用できるコマンドは次のとおりです。
mprof run
:実行ファイルの実行、メモリ使用量の記録mprof plot
:記録されたメモリ使用量をプロットする(デフォルトでは最後のもの)mprof list
:すべての記録されたメモリー使用量ファイルをユーザーフレンドリーな方法でリストします。mprof clean
:記録されたすべてのメモリ使用量ファイルを削除します。mprof rm
:特定の記録済みメモリ使用量ファイルを削除する
フォークされた子プロセスの追跡
マルチプロセスコンテキストでは、メインプロセスは、親プロセスとは別にシステムリソースが割り当てられている子プロセスを生成します。 これにより、デフォルトでは親プロセスのみが追跡されているため、メモリ使用量の報告が不正確になる可能性があります。 mprof
ユーティリティは、子プロセスの使用状況を追跡する2つのメカニズムを提供します。すべての子のメモリを親の使用量に合計し、各子個体を追跡します。
すべての子と親のメモリ使用量を組み合わせたレポートを作成するには、 profile
デコレータまたはmprof
コマンドライン引数としてinclude_children
フラグを使用しinclude_children
。
mprof run --include-children <script>
2番目の方法では、メインプロセスとは独立して各子を追跡し、子行をインデックスごとに出力ストリームに直列化します。 multiprocess
フラグを使用し、次のようにプロットします。
mprof run --multiprocess <script> mprof plot
これは、次のようなmatplotlibを使ってプロットを作成します:
include_children
フラグとmultiprocess
フラグを組み合わせて、プログラムの総メモリと各子を個別に表示することができinclude_children
。 APIを直接使用する場合、 memory_usage
からの戻り値には、メインメモリとともにネストされたリストに子メモリが含まれることに注意してください。
デバッガブレークポイントの設定
使用されるメモリの量に応じてブレークポイントを設定することができます。 つまり、スレッショルドを指定することができます。プログラムがスレッショルドで指定されたメモリより多くのメモリを使用すると、実行を停止してpdbデバッガに実行します。 それを使用するには、前のセクションで行ったように@profile
で関数を@profile
し、オプション-m memory_profiler --pdb-mmem=X
を使用してスクリプトを実行する必要があります。ここで、Xはメモリのしきい値を表す数値です。 例えば:
$ python -m memory_profiler --pdb-mmem=100 my_script.py
my_script.py
を実行し、装飾された関数でコードが100 MBを超えるとすぐにpdbデバッガにステップインします。
API
memory_profilerは、サードパーティのコードで使用されるいくつかの関数を公開しています。
memory_usage(proc=-1, interval=.1, timeout=None)
は、一定の時間間隔でメモリ使用量を返します。 最初の引数proc
は、何を監視すべきかを表します。 これは、プロセスのPID(必ずしもPythonプログラムではない)、評価されるべきいくつかのPythonコードを含む文字列、またはf(*args, **kw)
として評価される関数とその引数を含むタプル(f, args, kw)
f(*args, **kw)
。 例えば、
>>> from memory_profiler import memory_usage >>> mem_usage = memory_usage(-1, interval=.2, timeout=1) >>> print(mem_usage) [7.296875, 7.296875, 7.296875, 7.296875, 7.296875]
ここではmemory_profilerに、0.2秒の時間間隔で1秒間の現在のプロセスのメモリ消費量を取得するように指示しました。 PIDとして-1を与えました。これは現在のプロセスを意味する特殊な数値(PIDは通常正です)です。すなわち、現在のPythonインタプリタのメモリ使用量を取得しています。 したがって、私は平凡なPythonインタプリタから約7MBのメモリ使用量を得ています。 私がIPython(コンソール)で同じことを試してみると、私は29MBを得て、同じことをIPythonノートブックで試してみると、最大44MBになります。
Python関数のメモリ消費量を取得したい場合は、関数とその引数をタプル(f, args, kw)
指定する必要があります。 例えば:
>>> # define a simple function >>> def f(a, n=100): ... import time ... time.sleep(2) ... b = [a] * n ... time.sleep(1) ... return b ... >>> from memory_profiler import memory_usage >>> memory_usage((f, (1,), {'n' : int(1e6)}))
これは、コードf(1、n = int(1e6))を実行し、この実行中にメモリ消費量を返します。
報告
@profile(stream = fp)のようなデコレータにIOストリームをパラメータとして渡すことで、出力をログファイルにリダイレクトできます。
>>> fp=open('memory_profiler.log','w+') >>> @profile(stream=fp) >>> def my_func(): ... a = [1] * (10 ** 6) ... b = [2] * (2 * 10 ** 7) ... del b ... return a詳細はexamples / reporting_file.pyを参照してください。
Reporting via logger Module:
時々、RotatingFileHandlerを使用する必要があるときに特別にLoggerモジュールを使用すると便利です。
メモリプロファイラモジュールのLogFileを使用するだけで、出力をロガーモジュールにリダイレクトできます。
>>> from memory_profiler import LogFile >>> import sys >>> sys.stdout = LogFile('memory_profile_log')
Customized reporting:
memory_profilerの実行中にログファイルにすべてを送信するのは面倒なことがあり、TrueをreportIncrementFlagに渡すことで増分付きのエントリのみを選択できます。ここで、reportIncrementFlagはメモリプロファイラモジュールのLogFileクラスのパラメータです。
>>> from memory_profiler import LogFile >>> import sys >>> sys.stdout = LogFile('memory_profile_log', reportIncrementFlag=False)詳細については、examples / reporting_logger.pyを参照してください。
IPython統合
モジュールをインストールした後、IPythonを使うなら、%mprun、%% mprun、%memit、%% memitの魔法を使うことができます。
IPython 0.11+では、モジュールを直接拡張モジュールとして使用できます。 %load_ext memory_profiler
IPythonを起動するたびに起動するには、IPythonプロファイルの設定ファイル〜/ .ipython / profile_default / ipython_config.pyを編集して、このような拡張子を登録します(既に他の拡張子がある場合は、これをリストに追加してください) :
c.InteractiveShellApp.extensions = [ 'memory_profiler', ]
(設定ファイルが存在しない場合は、端末でipython profile create
を実行してipython profile create
)。
次に、%mprunまたは%% mprun magicコマンドを使用してIPythonから直接行ベースのレポートを取得することができます。 この場合、@profileデコレータをスキップし、代わりに-fパラメータを使用することができます。 ただし、関数my_funcはファイル内に定義する必要があります(Pythonインタプリタでインタラクティブに定義することはできません)。
In [1]: from example import my_func, my_func_2 In [2]: %mprun -f my_func my_func()
またはセルモードで:
In [3]: %%mprun -f my_func -f my_func_2 ...: my_func() ...: my_func_2()
私たちが定義するもう1つの有用な魔法は%memitです。これは%timeitに似ています。 次のように使用できます。
In [1]: %memit range(10000) peak memory: 21.42 MiB, increment: 0.41 MiB In [2]: %memit range(1000000) peak memory: 52.10 MiB, increment: 31.08 MiB
またはセルモード(セットアップコード付き):
In [3]: %%memit l=range(1000000) ...: len(l) ...: peak memory: 52.14 MiB, increment: 0.08 MiB
詳細は、魔法のドキュメンテーションを参照してください。
IPython 0.10では、IPython設定ファイル〜/ .ipython / ipy_user_conf.pyを編集してインストールし、以下の行を追加することができます。
# These two lines are standard and probably already there. import IPython.ipapi ip = IPython.ipapi.get() # These two are the important ones. import memory_profiler memory_profiler.load_ipython_extension(ip)
よくある質問
- Q:結果はどれくらい正確ですか?
- A:このモジュールは現在のプロセスが割り当てたメモリの量をオペレーティングシステムのカーネルに問い合わせることでメモリ消費量を取得します。これはPythonインタプリタで実際に使用されているメモリ量とは多少異なる場合があります。 また、ガベージコレクタがPythonでどのように動作するため、結果はプラットフォーム間でも、実行間でも異なる場合があります。
- Q:ウィンドウの下で動作しますか?
- A:はい、 psutilモジュールのおかげです。
サポート、バグ、ウィッシュリスト
サポートについては、 スタックオーバーフローに関する質問をして、 * memory-profiling *タグを追加してください。 問題、提案などをgithubのissueトラッカーに送信します。
開発に関する質問がある場合は、直接fabian@fseoane.netまでメールでお送りください
開発
最新ソースはgithubから入手できます:
memory_profilerを使用したプロジェクト
PySpeedIT ( memory_profilerの縮小バージョンを使用)
pydio-sync (memory_profilerの上にカスタムラッパーを使用)
著者
このモジュールは、Robert Kernのラインプロファイラに触発されたFabian PedregosaとPhilippe Gervaisによって書かれました。
Tomはpsutilモジュールを介してWindowsのサポートと速度の向上を追加しました。
Victorはpython3のサポート、バグ修正、一般的なクリーンアップを追加しました。
Vlad Niculaeは%mprunと%memit IPythonの魔法を追加しました。
Thomas KluyverはIPython拡張を追加しました。
Sagar UDAY KUMARは、レポートの生成機能と例を追加しました。
Dmitriy NovozhilovとSergei Lebedevはtracemallocのサポートを追加しました 。
Benjamin Bengfortは、個々の子プロセスの使用状況を追跡し、それらをプロットするためのサポートを追加しました。
Muhammad Haseeb Tariqは issue#152を修正しました。これによりインタープリタ全体が例外を発生させた関数にハングアップしました。
Juan Luis Canoはインフラを近代化し、さまざまなことを支援しました。
ライセンス
BSDライセンス。完全なテキストはファイルCOPYINGを参照してください。