php-memprof 是一個快速、準確的 PHP 記憶體分析擴展,可用於尋找記憶體洩漏的原因。
此擴充功能追蹤記憶體區塊的分配和釋放,以報告程式中每個函數、方法或檔案洩漏的記憶體量。
報告程序中任意點的未釋放內存
以 callgrind、pprof 或原始數組格式轉儲設定文件
可以追蹤 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 頁面上報告此軟體包的任何問題。
該擴充功能可以在命令列上加載,僅適用於一個腳本:
php -dextension=memprof.so script.php
或永久地在 php.ini 中:
extension=memprof.so
該擴充功能在不進行分析時沒有任何開銷,因此可以在開發環境中預設載入。
使用memprof
最簡單的方法是讓它在超出程式的記憶體限制時保存記憶體設定檔。
dump_on_limit
模式下啟用分析當滿足下列條件之一時,會在請求啟動時啟用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
模式下啟用分析。
在此模式下,如果程式超出記憶體限制(當 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
其他發行版很可能也有一個可供安裝的軟體包。
使用自製程式:https://formulae.brew.sh/formula/qcachegrind
從 https://sourceforge.net/projects/qcachegrindwin/ 下載
當滿足以下條件之一時,將在請求啟動時啟用分析:
環境變數MEMPROF_PROFILE
非空
$_GET["MEMPROF_PROFILE"]
非空
$_POST["MEMPROF_PROFILE"]
非空
MEMPROF_PROFILE
變數接受以逗號分隔的標誌清單。
有效MEMPROF_PROFILE
值的範例:
1
:非空:啟用分析
dump_on_limit
:啟用分析,將在記憶體限制上轉儲
native
:啟用分析,將分析本機分配
dump_on_limit,native
:啟用分析,將分析本機分配,將在記憶體限制上轉儲
有效標誌清單:
dump_on_limit
:將以 callgrind 格式將設定檔轉儲到/tmp
或C:WindowsTemp
中。可以使用memprof.output_dir
ini 設定更改輸出目錄。
native
:將分析本機malloc()
分配,而不僅僅是 PHP 的(這不是線程安全的,請參見下文)。
預設情況下,Memprof 不會追蹤本機分配,但可以透過將MEMPROF_PROFILE
設定為native
來啟用此功能。
本機分配是在 PHP 自己的記憶體分配器之外進行的分配。通常,libxml2(在 DOM 擴充中使用)等外部程式庫會進行本機分配。 PHP 也可以對持久性資源進行本機分配。
除了 PHP 自己的分配之外,啟用本機分配追蹤還將分析這些分配。
請注意,啟用本機追蹤後,如果本機庫使用線程,程式將崩潰,因為底層掛鉤不是線程安全的。
輸出檔案格式由memprof.output_format
ini 設定定義。選項有:
callgrind
(預設)
pprof
注意:這可能僅在從原始程式碼建置擴充功能(並且不使用 pecl 安裝)時可用,從 #101 開始。
傳回目前是否啟用記憶體分析(見上文)。
傳回是否啟用記憶體分析以及哪些分析功能已啟用(請參閱上文)。
以 callgrind 格式轉儲目前設定檔。可以使用 KCacheGrind 或 QCacheGrind 等工具將結果視覺化。
<phpmemprof_dump_callgrind(fopen("輸出", "w"));
這是 QcacheGrind 的截圖:
以 pprof 格式轉儲目前設定檔。
<?phpmemprof_dump_pprof(fopen("profile.heap", "w"));
該文件可以使用 google-perftools 的pprof
工具視覺化。 (請參閱下面的安裝說明。)
在網頁瀏覽器或gv
中顯示附註解的呼叫圖:
$ pprof --web profile.heap $ # or: $ pprof --gv profile.heap
每個函數輸出一行,並依照自己的記憶體使用量排序:
$ 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 或其他擴充衝突。如果您遇到這種情況,請報告。
目前分支支援 PHP 7.1 到 PHP 8。
php5 分支支援 PHP 5。
請參閱 INTERNALS.md