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