我对从ps和free看到的一些结果感到有些困惑。
在我的服务器上,这是结果 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
Run Code Online (Sandbox Code Playgroud)
我对 Linux 如何管理内存的理解是,它将磁盘使用情况存储在 RAM 中,以便每次后续访问都更快。我相信这是由“缓存”列指示的。此外,各种缓冲区存储在 RAM 中,如“缓冲区”列所示。
因此,如果我理解正确,“实际”用法应该是“-/+ 缓冲区/缓存”的“已使用”值,在这种情况下为 561。
所以假设所有这些都是正确的,抛出我的部分是ps aux
.
我对ps
结果的理解是,第 6 列 (RSS) 表示进程用于内存的大小(以千字节为单位)。
所以当我运行这个命令时:
[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52
Run Code Online (Sandbox Code Playgroud)
结果不应该是“-/+ 缓冲区/缓存”的“已使用”列free -m
吗?
那么,如何在 Linux 中正确确定进程的内存使用情况?显然我的逻辑有问题。
phe*_*mer 65
前几天无耻地从serverfault复制/粘贴我的答案:-)
linux 虚拟内存系统并不是那么简单。你不能只是添加了所有的RSS领域,并获得价值报告used
通过free
。造成这种情况的原因有很多,但我将介绍几个最大的原因。
当进程分叉时,父进程和子进程都将显示相同的 RSS。但是 linux 使用写时复制,因此两个进程实际上都在使用相同的内存。只有当其中一个进程修改内存时,它才会真正被复制。
这将导致free
数字小于top
RSS 总和。
RSS 值不包括共享内存。因为共享内存不属于任何一个进程,top
所以不包括在 RSS 中。
这将导致free
数字大于top
RSS 总和。
lem*_*eze 36
如果您正在寻找相加的内存数字,请查看smem:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
所以总共1Gb RAM = 654Mb用户空间进程+ 346Mb内核内存+ 16Mb免费
(提供或占用几 Mb)
总体而言,大约一半的内存用于缓存 (494Mb)。
额外问题:这里的用户空间缓存与内核缓存是什么?
顺便说一句,视觉上的尝试:
# smem --pie=name
Run Code Online (Sandbox Code Playgroud)
Byt*_*ger 17
一个非常好的工具是pmap
列出某个进程的当前内存使用情况:
pmap -d PID
Run Code Online (Sandbox Code Playgroud)
有关它的更多信息,请参阅手册页,man pmap
并查看每个系统管理员都应该知道的 20 个 Linux 系统监控工具,其中列出了我经常用来获取有关我的 Linux 机器的信息的出色工具。
2bc*_*2bc 10
运行顶部,点击h
寻求帮助,然后f
添加字段。您可以添加以下字段:
RSS
应用程序使用的物理内存量CODE
进程的可执行代码正在使用的内存总量DATA
- 专用于进程数据和堆栈的内存总量 (kb)在这 3 个之间,您应该有非常准确的结果。您还可以使用我推荐的 tophtop
或atop
.
编辑:如果你想要真正详细的信息,几乎忘记了。找到 PID 并找到以下文件。
PID=123
cat /proc/123/status
编辑 2:如果您能找到或拥有这本书:
优化 Linux 性能:Linux 性能工具实践指南
- 有一节第 5 章:性能工具:特定于进程的内存 - 它提供了比您想要的更多的信息。
ps
为您提供每个进程使用的内存量。其中一些内存是 mmapped 文件,在缓存中计数。其中一些内存(尤其是代码)与其他进程共享,因此如果您将 RSS 值相加,它会被计算多次。
“这个进程使用了多少内存?”没有正确的答案,因为它不仅取决于进程,还取决于环境。有许多不同的值可以称为进程的“内存使用量”,它们不匹配或不相加,因为它们计算的是不同的东西。
小智 5
正如其他人正确指出的那样,很难掌握进程使用的实际内存、共享区域的内容以及映射文件等。
如果你是一个实验者,你可以运行valgrind 和 massif。这对于临时用户来说可能会有点繁重,但随着时间的推移,您会了解应用程序的内存行为。如果应用程序 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 $!
Run Code Online (Sandbox Code Playgroud)
在 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
Run Code Online (Sandbox Code Playgroud)
并且 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
Run Code Online (Sandbox Code Playgroud)
在这里我们看到(非常有经验和非常高的信心)编译器分配了 77KB 的堆。
为什么要如此努力地获得堆使用?因为进程使用的所有共享对象和文本部分(在本例中为编译器)都不是很有趣。它们是一个过程的持续开销。事实上,该过程的后续调用几乎是“免费”的。
另外,比较和对比以下内容:
MMAP() 一个 1GB 的文件。您的 VMSize 将为 1+GB。但是您是驻留集大小将只是您导致被分页的文件部分(通过取消引用指向该区域的指针)。如果您“读取”整个文件,那么当您到达结尾时,内核可能已经将开头分页(这很容易做到,因为如果再次取消引用,内核确切地知道如何/在哪里替换这些页面) )。在任何一种情况下,VMSize 和 RSS 都不是您的内存“使用情况”的良好指标。你实际上还没有 malloc() 任何东西。
相比之下,Malloc() 和接触大量内存——直到你的内存被交换到磁盘。所以你分配的内存现在超过了你的 RSS。在这里,您的 VMSize 可能会开始告诉您一些事情(您的进程拥有的内存比实际驻留在 RAM 中的内存多)。但是仍然很难区分共享页面的虚拟机和交换数据的虚拟机。
这就是 valgrind/massif 变得有趣的地方。它向您展示了您有意分配的内容(无论您的页面状态如何)。
归档时间: |
|
查看次数: |
161574 次 |
最近记录: |