php-memprof は、メモリ リークの原因を見つけるために使用できる、PHP 用の高速かつ正確なメモリ プロファイリング拡張機能です。
この拡張機能は、メモリ ブロックの割り当てと解放を追跡し、プログラム内のすべての関数、メソッド、またはファイルによってリークされたメモリの量を報告します。
プログラム内の任意の時点で解放されていないメモリを報告します。
callgrind、pprof、または raw 配列形式でプロファイルをダンプします
PHP 自体およびネイティブ malloc によって割り当てられたメモリを追跡できます
php-memprof は libjudy と sys/queue.h に依存します。
Debian ベースのディストリビューションでは、依存関係は次のようにインストールできます。
# Debian or Ubuntu: apt install libjudy-dev
アルパインの場合:
# Alpine apk add judy-dev bsd-compat-headers
MacOS の場合:
# install libjudy dependency: brew install traildb/judy/judy
依存関係を必ずインストールしてから、次のことを行ってください。
pecl install memprof
MacOS の場合: JUDY_DIR=$(brew --prefix traildb/judy/judy) pecl install memprof
注libjudy が標準以外のパス (/usr または /usr/local ではない) にインストールされている場合は、以下の手動インストール方法を使用してください。
依存関係を必ずインストールしてから、次のことを行ってください。
ソースをダウンロードし、ソース ディレクトリで次のコマンドを実行します。
phpize ./configure make make install
注libjudy が非標準パス (/usr または /usr/local ではない) にインストールされている場合は、次のように指定できます。
./configure --with-judy-dir=/opt/homebrew/Cellar/judy/1.0.5
Arch Linux ユーザーは、 makepkg
または好みの AUR ヘルパーを使用して非公式 php-memprof パッケージをインストールすることを好む場合があります。 yay
を使用する場合は、たとえば次のようになります。
yay -S php-memprof
このパッケージに関する問題があれば、AUR ページで報告してください。
拡張機能は、1 つのスクリプトに対してのみ、コマンド ラインでロードできます。
php -dextension=memprof.so script.php
または、php.ini で永続的に:
extension=memprof.so
この拡張機能にはプロファイリングを行っていないときはオーバーヘッドがないため、デフォルトで開発環境にロードできます。
memprof
使用する最も簡単な方法は、プログラムのメモリ制限を超えたときにメモリ プロファイルを保存させることです。
dump_on_limit
モードでプロファイリングを有効にする次のいずれかが true の場合、 dump_on_limit
モードでのプロファイリングはリクエストの開始時に有効になります。
環境変数MEMPROF_PROFILE
はdump_on_limit
と等しい
$_GET["MEMPROF_PROFILE"]
dump_on_limit
と同じです
$_POST["MEMPROF_PROFILE"]
dump_on_limit
と同じです
コマンドラインスクリプトの場合、環境変数を設定できます。
MEMPROF_PROFILE=dump_on_limit php test.php
Web スクリプトの場合、 $_GET
変数を設定できます。
curl http://127.0.0.1/test.php?MEMPROF_PROFILE=dump_on_limit
または$_POST
変数:
curl -d MEMPROF_PROFILE=dump_on_limit http://127.0.0.1/test.php
注
memprof_enabled_flags()
関数を呼び出して、プロファイリングが現在dump_on_limit
モードで有効になっているかどうかを確認できます。
このモードでは、 memprof
がメモリ制限を超えた場合 (PHP がFatal error: Allowed memory size of 15728640 bytes exhausted (tried to allocate 1024 bytes)
エラーなどのエラーがトリガされた場合)、memprof はプロファイルを自動的に保存します。
デフォルトでは、プロファイルは/tmp
またはC:WindowsTemp
のmemprof.callgrind.*
結果を視覚化するために推奨される方法は、Kcachegrind (Linux の場合) または Qcachegrind (MacOS、Windows の場合) を使用することです。 Google Perftools もサポートされています。 memprof_dump_callgrind()
とそのバリアントのドキュメントを参照してください。
ほとんどのディストリビューションには、すぐにインストールできるkcachegrind
パッケージが含まれています。
たとえば、Ubuntu または Debian:
sudo apt install kcachegrind
他のディストリビューションにも、同様にインストールできるパッケージが用意されている可能性があります。
Homebrew を使用します: https://formulae.brew.sh/formula/qcachegrind
https://sourceforge.net/projects/qcachegrindwin/ からダウンロードします。
次のいずれかが true の場合、プロファイリングはリクエストの開始時に有効になります。
環境変数MEMPROF_PROFILE
が空ではありません
$_GET["MEMPROF_PROFILE"]
は空ではありません
$_POST["MEMPROF_PROFILE"]
は空ではありません
MEMPROF_PROFILE
変数は、フラグのカンマ区切りリストを受け入れます。
有効なMEMPROF_PROFILE
値の例:
1
: 空ではない: プロファイリングが有効です
dump_on_limit
: プロファイリングが有効になっており、メモリ制限に基づいてダンプされます。
native
: プロファイリングが有効になっており、ネイティブ割り当てをプロファイリングします。
dump_on_limit,native
: プロファイリングが有効になっており、ネイティブ割り当てをプロファイリングし、メモリ制限に基づいてダンプします。
有効なフラグのリスト:
dump_on_limit
: /tmp
またはC:WindowsTemp
に callgrind 形式でプロファイルをダンプします。出力ディレクトリはmemprof.output_dir
ini 設定で変更できます。
native
: PHP だけでなく、ネイティブのmalloc()
割り当てもプロファイリングします (これはスレッドセーフではありません。以下を参照してください)。
Memprof はデフォルトではネイティブ割り当てを追跡しませんが、これはMEMPROF_PROFILE
native
に設定することで有効にできます。
ネイティブ割り当ては、PHP 自体のメモリ アロケータの外部で行われる割り当てです。通常、libxml2 (DOM 拡張で使用) などの外部ライブラリはネイティブ割り当てを行います。 PHP は、永続リソースに対してネイティブ割り当てを行うこともできます。
ネイティブ割り当て追跡を有効にすると、PHP 自体の割り当てに加えて、これらの割り当てもプロファイリングされます。
ネイティブ トラッキングが有効な場合、ネイティブ ライブラリがスレッドを使用すると、基になるフックがスレッド セーフではないため、プログラムがクラッシュすることに注意してください。
出力ファイル形式は、 memprof.output_format
ini 設定で定義されます。オプションは次のとおりです。
callgrind
(デフォルト)
pprof
注: #101 の時点で、これは拡張機能がソースからビルドされている (pecl でインストールされていない) 場合にのみ使用可能です。
メモリ プロファイリングが現在有効かどうかを返します (上記を参照)。
メモリ プロファイリングとどのプロファイリング機能が有効かどうかを返します (上記を参照)。
現在のプロファイルを callgrind 形式でダンプします。結果は、KCacheGrind や QCacheGrind などのツールを使用して視覚化できます。
<phpmemprof_dump_callgrind(fopen("output", "w"));
これは QcacheGrind のスクリーンショットです。
現在のプロファイルを pprof 形式でダンプします。
<?phpmemprof_dump_pprof(fopen("profile.heap", "w"));
このファイルは、google-perftools のpprof
ツールを使用して視覚化できます。 (インストール手順については以下を参照してください。)
注釈付きのコールグラフを Web ブラウザまたはgv
に表示します。
$ pprof --web profile.heap $ # or: $ pprof --gv profile.heap
関数ごとに 1 行を出力し、メモリ使用量順に並べ替えます。
$ pprof --text profile.heap
pprof
インストール手順: Ubuntu: apt install google-perftools
。 Ubuntu では、ツールの名前はgoogle-pprof
であるため、上記の例のpprof
google-pprof
に置き換える必要があります。
現在のプロファイルを表す配列を返します。
<php$dump = memprof_dump_array();
配列は次の情報を公開します。
関数によってリークされた包括的および排他的メモリ (memprof_dump_array が呼び出されたときにまだ解放されていないメモリのみをカウントします)
関数の包含ブロックと排他ブロックの数 (割り当ての数。memprof_dump_array が呼び出されたときにまだ解放されていないブロックのみをカウント)
データはコールスタックに表示されます。こうすることで、関数が複数の場所から呼び出された場合に、どの呼び出しパスが最も多くのメモリ リークを引き起こしたかを確認することができます。
Array ( [memory_size] => 11578 [blocks_count] => 236 [memory_size_inclusive] => 10497691 [blocks_count_inclusive] => 244 [calls] => 1 [called_functions] => Array ( [main] => Array ( [memory_size] => 288 [blocks_count] => 3 [memory_size_inclusive] => 10486113 [blocks_count_inclusive] => 8 [calls] => 1 [called_functions] => Array ( [a] => Array ( [memory_size] => 4 [blocks_count] => 1 [memory_size_inclusive] => 10485825 [blocks_count_inclusive] => 5 [calls] => 1 [called_functions] => Array ( [b] => Array ( [memory_size] => 10485821 [blocks_count] => 4 [memory_size_inclusive] => 10485821 [blocks_count_inclusive] => 4 [calls] => 1 [called_functions] => Array ( [str_repeat] => Array ( [memory_size] => 0 [blocks_count] => 0 [memory_size_inclusive] => 0 [blocks_count_inclusive] => 0 [calls] => 1 [called_functions] => Array ( ) ) ) ) ) ) [memprof_dump_array] => Array ( [memory_size] => 0 [blocks_count] => 0 [memory_size_inclusive] => 0 [blocks_count_inclusive] => 0 [calls] => 1 [called_functions] => Array ( ) ) ) ) ) )
拡張機能のバージョンを文字列として返します。 version_compare()でバージョンを比較できます。
拡張機能は、xdebug、blackfire、または他の拡張機能と競合する可能性があります。そのような場合は、ご報告ください。
Current Branch は PHP 7.1 から PHP 8 をサポートします。
php5 ブランチは PHP 5 をサポートします。
INTERNALS.md を参照してください。