我对看到的一些结果有点困惑附注和自由的。
在我的服务器上,这是结果free -m
[root@server ~]# free -m
total used free shared buffers cached
Mem: 2048 2033 14 0 73 1398
-/+ buffers/cache: 561 1486
Swap: 2047 11 2036
我对Linux如何管理内存的理解是,它将磁盘使用情况存储在RAM中,以便后续的每次访问更快。我相信这是由“缓存”列指示的。此外,各种缓冲区存储在 RAM 中,如“缓冲区”列中所示。
因此,如果我理解正确,“实际”使用量应该是“-/+ buffers/cache”的“已使用”值,在本例中为 561。
因此,假设所有这些都是正确的,那么让我困惑的部分是ps aux
.
我对ps
结果的理解是,第六列 (RSS) 代表进程使用的内存大小(以千字节为单位)。
所以当我运行这个命令时:
[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52
结果不应该是“-/+ buffers/cache”的“used”列吗free -m
?
那么,如何正确判断Linux中进程的内存使用情况呢?显然我的逻辑有问题。
答案1
无耻地复制/粘贴我的答案服务器故障就在前几天:-)
Linux 虚拟内存系统并不那么简单。您不能仅将所有 RSS 字段相加并获取 报告的used
值free
。造成这种情况的原因有很多,但我将列出几个最重要的原因。
当进程分叉时,父进程和子进程都会显示相同的 RSS。然而,Linux 采用写时复制,因此两个进程实际上使用相同的内存。只有当其中一个进程修改了内存时,它才会真正被复制。
这将导致该free
数字小于top
RSS 总和。RSS 值不包括共享内存。由于共享内存不属于任何一个进程,因此
top
不将其包含在 RSS 中。
这将导致该free
数字大于top
RSS 总和。
这些数字可能无法相加还有许多其他原因。这个答案只是想表明内存管理非常复杂,您不能仅添加/减去单个值来获得总内存使用量。
答案2
如果您正在寻找加起来的内存数字,请查看斯梅姆:
smem 是一个可以提供有关 Linux 系统内存使用情况的大量报告的工具。与现有工具不同,smem 可以报告比例集大小 (PSS),这是虚拟内存系统中库和应用程序使用的内存量的更有意义的表示。
由于大部分物理内存通常在多个应用程序之间共享,因此称为驻留集大小 (RSS) 的内存使用量标准度量将显着高估内存使用量。相反,PSS 会测量每个应用程序对每个共享区域的“公平份额”,以给出切合实际的测量结果。
例如这里:
# smem -t
PID User Command Swap USS PSS RSS
...
10593 root /usr/lib/chromium-browser/c 0 22868 26439 49364
11500 root /usr/lib/chromium-browser/c 0 22612 26486 49732
10474 browser /usr/lib/chromium-browser/c 0 39232 43806 61560
7777 user /usr/lib/thunderbird/thunde 0 89652 91118 102756
-------------------------------------------------------------------------------
118 4 40364 594228 653873 1153092
这里有趣的专栏也是如此PSS
,因为它考虑了共享内存。
不像RSS
将其相加才有意义。我们在这里获得了用户态进程总共 654Mb 的空间。
系统范围的输出告诉我们剩下的事情:
# smem -tw
Area Used Cache Noncache
firmware/hardware 0 0 0
kernel image 0 0 0
kernel dynamic memory 345784 297092 48692
userspace memory 654056 181076 472980
free memory 15828 15828 0
----------------------------------------------------------
1015668 493996 521672
因此 1Gb RAM 总计= 654Mb用户态进程+ 346Mb内核内存+ 16Mb可用空间
(给予或减少几 Mb)
总体而言,大约一半的内存用于缓存 (494Mb)。
奖金问题:这里的用户态缓存与内核缓存是什么?
顺便说一句,对于一些视觉尝试:
# smem --pie=name
答案3
一个非常好的工具是pmap
列出某个进程的当前内存使用情况:
pmap -d PID
有关它的更多信息,请参阅手册页man pmap
并查看每个系统管理员都应该知道的 20 个 Linux 系统监控工具,其中列出了我经常用来获取有关我的 Linux 机器的信息的优秀工具。
答案4
正如其他人正确指出的那样,很难掌握进程使用的实际内存、共享区域、映射文件等。
如果您是实验者,您可以运行瓦尔格林德和地块。对于普通用户来说,这可能有点繁重,但随着时间的推移,您将了解应用程序的内存行为。如果应用程序 malloc() 正是它所需要的,那么这将为您提供进程的真实动态内存使用情况的良好表示。但这个实验可能会“中毒”。
让事情变得复杂的是,Linux 允许您过度使用你的记忆。当您 malloc() 内存时,您就表明了消耗内存的意图。但是,直到您将一个字节写入分配的“RAM”的新页面后,分配才真正发生。您可以通过编写并运行一个小 C 程序来向自己证明这一点,如下所示:
// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
void *p;
sleep(5)
p = malloc(16ULL*1024*1024*1024);
printf("p = %p\n", p);
sleep(30);
return 0;
}
# Shell:
cc test.c -o test && ./test &
top -p $!
在 RAM 小于 16GB 的计算机上运行此程序,瞧!您刚刚获得了 16GB 内存! (不,不是真的)。
请注意,top
您看到“VIRT”为 16.004G,但 %MEM 为 0.0
使用 valgrind 再次运行:
# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30
Massif 说“所有 allocs() 的总和 = 16GB”。所以这不是很有趣。
但是,如果你在理智的过程:
# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30
--------------------------------------------------------------------------------
Command: cc test.c -o test
Massif arguments: (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------
KB
77.33^ :
| #:
| :@::@:#:
| :::::@@::@:#:
| @:: :::@@::@:#:
| ::::@:: :::@@::@:#:
| ::@:::@:::::@:: :::@@::@:#:
| @::@:::@:::::@:: :::@@::@:#:
| @::@:::@:::::@:: :::@@::@:#:
| :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
| :@@ :@::@:::@:::::@:: :::@@::@:#:
| :@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :@::::@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :::::@::::@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| :::::::@::::@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| ::::::::@::::@@:@@ :@::@:::@:::::@:: :::@@::@:#:
| ::::::::@::::@@:@@ :@::@:::@:::::@:: :::@@::@:#:
0 +----------------------------------------------------------------------->Mi
0 1.140
在这里我们看到(非常凭经验并且非常有信心)编译器分配了 77KB 堆。
为什么要如此努力地获取堆使用情况?因为进程使用的所有共享对象和文本部分(在本例中为编译器)都不是很有趣。它们是流程的持续开销。事实上,该过程的后续调用几乎是“免费”的。
另外,比较和对比以下内容:
MMAP() 一个 1GB 文件。您的 VMS 大小将为 1+GB。但是您的驻留集大小将只是您导致分页的文件部分(通过取消引用指向该区域的指针)。如果您“读取”整个文件,那么当您读到末尾时,内核可能已经调出开头部分(这很容易做到,因为内核确切地知道如果再次取消引用,如何/在哪里替换这些页面)。无论哪种情况,VMSize 和 RSS 都不能很好地指示内存“使用情况”。您实际上还没有 malloc() 任何东西。
相比之下,Malloc() 会占用大量内存——直到内存被交换到磁盘。所以你分配的内存现在超过了你的 RSS。在这里,您的 VMSize 可能会开始告诉您一些信息(您的进程拥有的内存比 RAM 中实际驻留的内存多)。但仍然很难区分共享页面的虚拟机和交换数据的虚拟机。
这就是 valgrind/massif 变得有趣的地方。它向你展示了你故意地已分配(无论页面的状态如何)。