我注意到,top
或ps
报告作为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。
答案 0 :(得分:6)
memory_get_usage
报告PHP进程分配的内存以运行脚本。 ps
报告PHP进程本身使用的内存,其中包括用于脚本的内存。 PHP进程使用了许多外部库,它们都可以在没有PHP进程知道的情况下分配内存。
所以memory_get_usage
和ps
固有地衡量不同的事情,并应报告不同的数字。这一切都取决于你如何定义“实际内存使用”。据我所知,在您的情况下,您对PHP进程的内存使用更感兴趣。然后ps
的输出对您更有意义。但是你可以很容易地发现即使ps
报告的RSS值在现代操作系统和共享记忆的世界中也不是那么黑白。
另见:
答案 1 :(得分:5)
应该强调ps
和memory_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设置与之比较的数字。
如果你想看看你可以运行多少工人,请注意PHP不会共享很多内存,除了内核可以共享库内存和opcache,它共享结构(操作码,类信息等)。因此,共享内存对您来说应该不重要。因此,最重要的价值应该是USS。
答案 2 :(得分:2)
在发布以下命令之一时,您可能会发现有趣的事情:
cat /proc/PID_NUMBER/smaps
pmap -d PID_NUMBER