PHP 实际使用了多少内存


How much memory is PHP actually using?

我注意到topps报告PHP进程的内存使用情况与进程本身认为其使用的内容(使用memory_get_usage(之间存在很大差异。

进程实际使用了多少内存?

与我的一个应用程序一起运行以下代码时:

echo "Memory usage: " . pretty_bytes(memory_get_usage()) . PHP_EOL;
echo "Peak memory usage: " . pretty_bytes(memory_get_peak_usage()) . PHP_EOL;
echo "'Actual' memory usage: " . pretty_bytes(memory_get_usage(true)) . PHP_EOL;
echo "'Actual' peak memory usage: " . pretty_bytes(memory_get_peak_usage(true)) . PHP_EOL;
$ps_output = exec("ps --pid " . getmypid() . " --no-headers -o rss");
echo "'Memory usage according to ps: " . pretty_bytes(intval($ps_output) * 1000);

随机点的输出为:

Memory usage: 4.77 MB
Peak memory usage: 4.99 MB
'Actual' memory usage: 5.00 MB
'Actual' peak memory usage: 5.00 MB
Memory usage according to ps: 17.66 MB

在我的特殊情况下,这是一个问题,因为我正在运行相当多的工作线程和守护进程。

当我为每个守护程序将 PHP 内存限制设置为 128 MB 时,根据

PHP 自己的测量,这些进程只有在达到 128 MB 时才会被杀死。但是,根据 ps ,到那时,每个进程将使用大约 200 MB。

应该强调的是,psmemory_get_usage(true)报告的数值到底是什么。

ps -o rss报告实际驻留集大小。依赖此值是一个很大的陷阱,因为它不包括最终换出的内存。一般来说,你想要USS唯一集大小,它基本上是非共享内存(看看smem(8)(。它是内核实际为该进程映射页面的非共享内存量,即在 RAM 或交换文件中物理存在未共享内存。这是您可以获得的"真实"内存使用情况的尽可能接近。[另请参阅/proc/$PID/smaps以获取详细的概述,如 IVO GELOV 的回答中所述,从技术上讲,您可以通过解析该虚拟文件来计算您想要计算的内存。

关于memory_get_usage(),这报告了使用PHP内部内存管理器的系统实际分配的堆内存。这意味着,直接使用系统其他内存管理器(mmap(2)malloc(3)(的库不会在这里公开它们的内存使用情况。[例如,这就是为什么mysqlnd确实显示了很多内存使用量,而libmysqlclient没有 - 后者在内部使用malloc()

如果将true作为第一个参数传递,即 memory_get_usage(true),它返回 PHP 的内部内存管理器从系统请求的内存总量。这个数字总体上略有,但不比memory_get_usage(false)高多少。它也是与memory_limit INI 设置进行比较的数字。

如果你想看看你可以运行多少worker,请注意PHP不共享太多内存,除了内核可以共享库内存和opcache,后者共享结构(操作码,类信息等(。因此,共享内存对您来说应该不重要。因此,对您来说最重要的价值应该是USS。

memory_get_usage报告 PHP 进程为运行脚本而分配的内存。 ps报告 PHP 进程本身使用的内存,其中包括用于脚本的内存。PHP 进程使用许多外部库,这些库都可以分配它们的内存,而 PHP 进程不知道这一点。

因此,memory_get_usageps本质上衡量不同的东西,应该报告不同的数字。这一切都归结为您如何定义"实际内存使用情况"。我知道在您的情况下,您对PHP进程的内存使用情况更感兴趣。那么ps的输出与你更相关。但是你可以很容易地发现,即使是ps报告的RSS值,在现代操作系统和共享记忆的世界里也不是那么黑白分明。

另请参阅:

  • http://php.net/manual/en/function.getrusage.php
  • 如何测量应用程序或进程的实际内存使用情况?

在发出以下命令之一时,您可能会发现有趣的事情:

cat /proc/PID_NUMBER/smaps
pmap -d PID_NUMBER