在 PHP 中跟踪内存使用情况
Posted
技术标签:
【中文标题】在 PHP 中跟踪内存使用情况【英文标题】:Tracking Memory Usage in PHP 【发布时间】:2011-01-18 10:28:44 【问题描述】:我正在尝试跟踪处理 URL 的脚本的内存使用情况。基本思想是在将另一个 URL 添加到 cURL 多处理程序之前检查是否有合理的缓冲区。我正在使用“滚动 cURL”概念,它在多处理程序运行时处理 URL 数据。这意味着我可以通过在每次处理现有 URL 并将其删除时从池中添加一个新 URL 来保持 N 个连接处于活动状态。
我使用memory_get_usage()
获得了一些积极的结果。添加real_usage
标志有帮助(不太清楚“系统”内存和“emalloc”内存之间的区别,但系统显示更大的数字)。 memory_get_usage()
确实会随着 URL 的添加而上升,然后随着 URL 集的耗尽而下降。但是,我刚刚超过了 32M 的限制,我最后一次内存检查是 ~18M。
每次 cURL 多信号返回请求时,我都会轮询内存使用情况。由于多个请求可能同时返回,有可能是一堆URL同时返回数据,实际占用内存14M。但是,如果memory_get_usage()
是准确的,我想这就是正在发生的事情。
[更新:我猜应该在询问之前运行更多测试,增加了 php 的内存限制(但在脚本中保留了相同的“安全”数量)并且报告的内存使用量确实从低于我自己设定的 25M 到超过 32M 的限制。然后,正如预期的那样,随着未添加的 URL 缓慢下降。但我会留下一个问题:这是正确的方法吗?]
我可以这样信任memory_get_usage()
吗?是否有更好的替代方法来获取内存使用情况(我见过一些脚本解析 shell 命令的输出)?
【问题讨论】:
【参考方案1】:好吧,我的 PHP 脚本从来没有真正遇到过内存问题,所以我认为我对找出问题的原因没有多大帮助,但我可以建议你获得一个 PHP 加速器,你会注意到严重的性能提升和内存使用率下降。以下是加速器列表和一篇比较其中一些加速器的文章(其中任何加速器的性能提高了 3 倍)
Wikipedia List
Benchmark
基准测试已有 2 年历史,但您知道性能提升了。
如果您必须在 PHP 中增加内存限制,即使使用加速器仍然存在问题。打开你的 php.ini 并找到:
memory_limit = 32M;
只是增加一点。
【讨论】:
是的,这就是这个项目未来的全部内容,现在只是尽可能地保持脚本一致。问题是我希望它使用它提供的内存。【参考方案2】:我还假设memory_get_usage()
是安全的,但我想您可以比较这两种方法并自行决定,这里有一个解析系统调用的函数:
function Memory_Usage($decimals = 2)
$result = 0;
if (function_exists('memory_get_usage'))
$result = memory_get_usage() / 1024;
else
if (function_exists('exec'))
$output = array();
if (substr(strtoupper(PHP_OS), 0, 3) == 'WIN')
exec('tasklist /FI "PID eq ' . getmypid() . '" /FO LIST', $output);
$result = preg_replace('/[\D]/', '', $output[5]);
else
exec('ps -eo%mem,rss,pid | grep ' . getmypid(), $output);
$output = explode(' ', $output[0]);
$result = $output[1];
return number_format(intval($result) / 1024, $decimals, '.', '');
【讨论】:
你最好使用“--pid”而不是 grep,因为有一天你可能会得到一个等于你正在寻找的 PID 的 RSS 值并最终得到 2 行 你的代码返回的内存单位是多少??【参考方案3】:real_usage
这样工作:
Zend 的内存管理器不会对它需要的每个块都使用系统 malloc。相反,它分配一大块系统内存(以 256K 为增量,可以通过设置环境变量 ZEND_MM_SEG_SIZE
进行更改)并在内部对其进行管理。所以,内存使用有两种:
-
引擎从操作系统中占用了多少内存(“实际使用情况”)
应用程序实际使用了多少内存(“内部使用量”)
memory_get_usage()
可以返回其中任何一个。哪一个对您更有用取决于您正在研究什么。如果您正在考虑优化特定部分的代码,“内部”可能对您更有用。如果您要在全球范围内跟踪内存使用情况,“真实”会更有用。 memory_limit
限制了“真实”数字,因此一旦从系统中取出限制允许的所有块并且内存管理器无法分配请求的块,分配就会失败。请注意,在这种情况下,“内部”使用量可能低于限制,但分配仍可能因碎片而失败。
另外,如果你正在使用一些外部内存跟踪工具,你可以设置这个
环境变量USE_ZEND_ALLOC=0
将禁用上述机制并使引擎始终使用malloc()
。这将有更差的性能,但允许您使用 malloc 跟踪工具。
另见an article about this memory manager,它也有一些代码示例。
【讨论】:
404 试图关注文章链接。唉。 @MichaelCordingley,试试这个:web.archive.org/web/20130719064612/http://www.ibm.com/… 我有memory_get_peak_usage(false)
报告为 7.65 MiB,而实际使用 memory_get_peak_usage(true)
报告为 4 MiB(一致)。我一个接一个地打电话。这怎么可能?我正在使用 PHP 7.3。
我应该补充一点,Opcache 未启用,Xdebug 未加载(既未加载也未启用,即php -m
不报告 Xdebug)。【参考方案4】:
使用xdebug,因为它最近(1 月 29 日)更新为现在包含内存分析信息。它跟踪函数调用以及它们消耗的内存量。这使您可以非常深入地了解您的代码,并至少让您朝着意识到问题的方向前进。
该文档很有帮助,但本质上,安装它启用分析 xdebug.profiler_enable = 1
并将输出 xdebug.profiler_output_dir=/some/path
提供给诸如 qcachegrind 之类的工具来完成繁重的工作,让您直观地看到它。
【讨论】:
以上是关于在 PHP 中跟踪内存使用情况的主要内容,如果未能解决你的问题,请参考以下文章
如何跟踪 Visual Studio 2017(C++)中的内存使用情况?