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


63

我对从psfree看到的一些结果有些困惑。

在我的服务器上,这是由于 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中,如“缓冲区”列中所示。

因此,如果我理解正确,那么“实际”用法应该是“-/ +缓冲区/缓存”的“已使用”值,在这种情况下为561。

因此,假设所有这些信息都是正确的,那么让我吃惊的部分是的结果ps aux

我对ps结果的理解是,第六列(RSS)代表进程用于内存的千字节大小。

因此,当我运行以下命令时:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

结果不应该是来自“-/ +缓冲区/缓存”的“已使用”列free -m吗?

那么,如何正确确定Linux中进程的内存使用情况?显然我的逻辑是有缺陷的。


这个问题很受欢迎,我想我应该分享htop笔者对前一天遇到的一个类似问题的答案... 如何从/ proc / meminfo(如htop)计算内存使用情况
tgogos

Answers:


57

前几天在serverfault上问了这个完全相同的问题:-)

linux虚拟内存系统并不是那么简单。你不能只是添加了所有的RSS领域,并得到报告的值used通过free。造成这种情况的原因很多,但我将介绍其中的几个最大原因。

  • 进程分叉时,父级和子级都将显示相同的RSS。但是linux采用了copy-on-write这种方式,以便两个进程实际上都使用相同的内存。仅当其中一个进程修改了内存时,它才实际被复制。因此,这将导致free数比小topRSS总和。

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


1
到目前为止,这是我在任何堆栈交换站点上获得的最佳答案。因此,我想知道的具体内容。这对于我的情况而言特别准确,因为我正在处理一个我编写的进程分叉的程序,但是大部分占用空间都在它们使用的库中。
GoldenNewby 2012年

这个答案的问题是,计算RSS和SHR的总和通常比使用的内存少得多。例如,在我拥有的VPS上,使用的内存为380MB,而所有RSS和SHR的总和为90MB。
user239558

2
@ user239558正如我在答案中提到的那样,数字没有加起来的原因有很多,我只列出了其中两个。还有很多其他的数字。缓存,平板,大页面等
Patrick

2
大概几年后,在您回答了这个问题之后,我仍然(至少)感到困惑。您说过RSS值不包括共享内存,但是这个答案说:“只要共享库中的页面实际上在内存中,它就包括共享库中的内存”。现在我不知道该相信哪一个...也许我在这里错过了一些细微的区别...
Naitree

1
@Naitree“共享库”!=“共享内存”。共享内存类似于shmgetmmap。关于内存的措辞非常棘手。在错误的位置使用错误的单词会完全弄乱句子的含义。
Patrick

30

如果您正在寻找加起来的内存编号,请查看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 

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

在此处输入图片说明


14

一个非常好的工具是pmap列出特定进程的当前内存使用情况:

pmap -d PID

有关它的更多信息,请参见手册页,man pmap并查看SysAdmin每个人都应该知道的20种Linux系统监视工具,其中列出了我经常用来获取有关Linux机器信息的出色工具。


那是一个很酷的工具,但是并不能真正解决我的问题。我试图弄清楚如何有效地确定服务器上的“实际”内存使用情况。
GoldenNewby 2012年

3
@GoldenNewby不存在进程的“实际”内存使用情况。系统的实际内存使用量free告诉您。
吉尔斯(Gilles)2012年

pmap -x PID还包括一个RSS列,该列通常对于了解进程的RSS总和在哪里很有用(例如,通过观察到top)。
maxschlepzig 2014年

10

运行顶部,h寻求帮助,然后f添加字段。您可以添加以下字段:

  • RSS 应用程序正在使用的物理内存量
  • CODE 进程的可执行代码正在使用的内存总量
  • DATA -专用于进程的数据和堆栈的内存总量(kb)

在这3个之间,您应该获得非常准确的结果。您也可以使用更详细的替代品来替代我推荐的htopatop

编辑:如果您想要真正的详细信息,几乎忘了。查找PID,并保存以下文件。

PID=123

cat /proc/123/status

编辑2:如果可以找到它或拥有这本书:

优化Linux性能:Linux性能工具动手指南

-有一个章节第5章:性能工具:特定于进程的内存-它具有比您想要的更多的信息。


默认情况下,top顶部具有该过程的RSS大小。在我的示例中,Top给出的结果与“ ps aux”相同。我的问题是,所有进程的合并RSS如何比整个服务器上的“活动”内存使用率高得多?
GoldenNewby 2012年

5

ps给您每个进程使用的内存量。某些内存是映射文件,这些文件计入缓存。某些内存(尤其是代码)与其他进程共享,因此,如果您将RSS值相加,则会被多次计数。

对于“该进程使用了​​多少内存?”没有正确的答案,因为它不仅取决于进程,还取决于环境。您可以将许多不同的值称为流程的“内存使用情况”,它们不匹配或相加,因为它们在计算不同的事物。


4

正如其他人正确指出的那样,很难掌握进程使用的实际内存,共享区域的内容,mmap文件和其他内容。

如果您是实验者,则可以运行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 $!

在内存少于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文件。您的VMSize将为1 + GB。但是,您的居民集大小将仅是导致分页的文件部分(通过取消引用指向该区域的指针)。而且,如果您“读取”整个文件,那么到结束时,内核可能已经分页了开头(这很容易做到,因为如果再次取消引用,内核确切地知道如何/在何处替换这些页面)。无论哪种情况,VMSize和RSS都不能很好地指示您的内存“使用情况”。您实际上并没有malloc()进行任何操作。

相比之下,Malloc()并触摸很多内存-直到您的内存被交换到磁盘上。因此,您分配的内存现在超过了RSS。在这里,您的VMSize可能会告诉您一些信息(您的进程拥有的内存比实际驻留在RAM中的内存更多)。但是,仍然很难区分共享页面的VM和交换数据的VM。

这就是valgrind / massif变得有趣的地方。它显示您有意分配的内容(无论页面状态如何)。


我有一个问题要问你。我有一个mlock()s所有mmap文件的进程。有没有一种方法可以确定该内存中有多少被主动使用-例如在过去一两分钟内已读取或写入了多少内存?
迈克尔·马丁内斯

2

试试这个:它将为您提供所有正在运行的所有进程实际使用的总RAM,以MB为单位

ps -eo size,pid,user,command --sort -size | awk '
  { hr=$1/1024 ; printf("%13.2f Mb ",hr) } 
  { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }
  ' | awk '{total=total + $1} END {print total}'

size报告ps几乎没有关系,实际的内存使用情况。这是每个进程的虚拟大小,不一定分配内存。它还不包括分配的某些细分。
马特2014年

-2

它会告诉您用户有多少内存。

#!/bin/bash
total_mem=0

printf "%-10s%-10s\n" User MemUsage

while read u m
do
        [[ $old_user != $u ]] && {  printf "%-10s%-0.1f\n" $old_user $total_mem;
                                    total_mem=0; }
        total_mem="$(echo $m + $total_mem | bc)"
        old_user=$u

done < <(ps --no-headers -eo user,%mem| sort -k1)

#EOF

-3

使用此命令以%为单位查找内存利用率。

使用的内存:

grep Mem | awk '{print $3/$2 * 100.0}'

可用内存

grep Mem | awk '{print $4/$2 * 100.0}'

3
Errr,这不会做任何事情。grep只会坐在那里等待输入。
mattdm 2015年

1
这应该是free -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.