正确确定Linux中的内存使用情况

正确确定Linux中的内存使用情况

我对看到的一些结果有点困惑附注自由的

在我的服务器上,这是结果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 字段相加并获取 报告的usedfree。造成这种情况的原因有很多,但我将列出几个最重要的原因。

  • 当进程分叉时,父进程和子进程都会显示相同的 RSS。然而,Linux 采用写时复制,因此两个进程实际上使用相同的内存。只有当其中一个进程修改了内存时,它才会真正被复制。
    这将导致该free数字小于topRSS 总和。

  • RSS 值不包括共享内存。由于共享内存不属于任何一个进程,因此top不将其包含在 RSS 中。
    这将导致该free数字大于topRSS 总和。

这些数字可能无法相加还有许多其他原因。这个答案只是想表明内存管理非常复杂,您不能仅添加/减去单个值来获得总内存使用量。

答案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 变得有趣的地方。它向你展示了你故意地已分配(无论页面的状态如何)。

相关内容