• 有关linux 系统/进程使用内存量


    对于linux free 命令:

    free输出的第一行是从一个系统的角度看系统内存的使用情况

        buffer是用于存放要输出到disk(块设备)的数据的

        cache是存放从disk上读出的数据

        这二者是为了提高IO性能的,并由OS管理。

    free输出的第二行是从一个应用程序的角度看系统内存的使用情况

        对于-buffers/cache,表示一个应用程序认为系统被用掉多少内存;

        对于+buffers/cache,表示一个应用程序认为系统还有多少内存;

    所以对于系统来说要看第一行的free,应用程序要看第二行的free

    对于linux 单个进程来说:

    • 进程所申请的内存不一定真正会被用到
    • 真正用到了的内存也不一定是只有该进程自己在用 (比如动态共享库)

    VSZ:进程内存空间的大小  如果进程映射了100M的内存, 进程的地址空间将报告为100M内存. 事实上, 这个大小不是一个程序实际使用的内存数

    RSS:驻留物理内存中的内存大小(VSZ 和RSS 可以由ps aux 得到)"Resident Set Size", 实际驻留"在内存中"的内存数. 不包括已经交换出去的代码. 举一个例子: 如果你有一个程序使用了100K内存, 操作系统交换出40K内存, 那么RSS为60K. RSS还包括了与其它进程共享的内存区域. 这些区域通常用于libc库等.

    SHARE: RSS中与其它进程共享的内存部分大小.  SHARE 包含在RSS

    VMSIZE: 一个进程占用的总的地址空间大小. 它包括了没有映到内存中的页面.

            VMSIZE = VSZ + 没有映射到内存的页面

            VSZ =RSS + 映射了但是没有使用的内存页面(交换出去了)

            RSS = SHARE + Private RSS

    Private RSS: 映射到内存中的页面, 这些页面仅由进程单独使用. 这也是我们最关心地方: 进程实际占用的内存数.主要通过读/proc/$pid/smaps获得(要想获得准确的,适用EXMAP工具)

    ps命令计算的进程内存使用它是假设系统上只存在这唯一运行的进程时,此进程所占用的内存,所以不准:

    RSS里面其实包括了共享库的内存大小,它计算的是所有共享库被它使用。

    top命令的输出:

    VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    SWAP 进程使用的虚拟内存中,被换出的大小,单位kb。
    RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    CODE 可执行代码占用的物理内存大小,单位kb
    DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
    SHR 共享内存大小,单位kb

    top 内存利用率是由 RES/总的物理内存得到的

    RES = RSS

    VIRT = VSZ

    这两个命令其实是一套体系的

    下面的是一个什么体系?

    Virtual memory :     52396 KB
    Effective VM    :     52120 KB
    Mapped          :    352 KB
    Effective mapped:     76.6 KB
    Sole use        :     72 KB

    Per file memory use
    ld-2.3.4.so                   : VM   94208 B, M   90112 B, S    8192 B
    prog                          : VM    8192 B, M    8192 B, S    8192 B
    libc-2.3.4.so                 : VM    1180 KB, M 221184 B, S   16384 B

    有效的实际使用内存 = 该进程独占的内存 + 共享的内存A /共享A的进程数目 + 共享的内存B /共享B的进程数目 + ...

    ---------------------------------------------------------------我是邪恶的分割线-----------------------------------------------------------------

    解释一下Linux上free命令的输出。

      下面是free的运行结果,一共有4行。为了方便说明,我们加上了列号。这样可以把free的输出看成一个二维数组FO(Free Output)。例如:

    • FO[2][1] = 999212
    • FO[3][2] = 305404
          1     2    3    4       5      6
      1
                            total    used      free  shared buffers  cached
      2 Mem:                999212  967476     31736       0   50668  223000
      3  -/+ buffers/cache:         693808    305404
      4 Swap:              2048276  154524   1893752    

      free的输出一共有四行,第四行为交换区的信息,分别是交换的总量(total),使用量(used)和有多少空闲的交换区(free),这个比较清楚,不说太多。

      free输出地第二行和第三行是比较让人迷惑的。这两行都是说明内存使用情况的。第一列是总量(total),第二列是使用量(used),第三列是可用量(free)。第一行的输出时从操作系统(OS)来看的。也就是说,从OS的角度来看,计算机上一共有:

    • 999212KB(缺省时free的单位为KB)物理内存,即FO[2][1];
    • 在这些物理内存中有967476KB(即FO[2][2])被使用了;
    • 还用31736KB(即FO[2][3])是可用的;

    这里得到第一个等式:

    • FO[2][1] = FO[2][2] + FO[2][3]

    FO[2][4]表示被几个进程共享的内存的,现在已经deprecated,其值总是0(当然在一些系统上也可能不是0,主要取决于free命令是怎么实现的)。

    FO[2][5]表示被OS buffer住的内存。FO[2][6]表示被OS cache的内存。在有些时候buffer和cache这两个词经常混用。不过在一些比较低层的软件里是要区分这两个词的,看老外的洋文:

    • A buffer is something that has yet to be "written" to disk.
    • A cache is something that has been "read" from the disk and stored for later use.

    也就是说buffer是用于存放要输出到disk(块设备)的数据的,而cache是存放从disk上读出的数据。这二者是为了提高IO性能的,并由OS管理。

    Linux和其他成熟的操作系统(例如windows),为了提高IO read的性能,总是要多cache一些数据,这也就是为什么FO[2][6](cached memory)比较大,而FO[2][3]比较小的原因。我们可以做一个简单的测试:

    1. 释放掉被系统cache占用的数据;
      echo 3>/proc/sys/vm/drop_caches
    2. 读一个大文件,并记录时间;
    3. 关闭该文件;
    4. 重读这个大文件,并记录时间;

    第二次读应该比第一次快很多。原来我做过一个BerkeleyDB的读操作,大概要读5G的文件,几千万条记录。在我的环境上,第二次读比第一次大概可以快9倍左右。

      free输出的第二行是从一个应用程序的角度看系统内存的使用情况。

    • 对于FO[3][2],即-buffers/cache,表示一个应用程序认为系统被用掉多少内存;
    • 对于FO[3][3],即+buffers/cache,表示一个应用程序认为系统还有多少内存;

    因为被系统cache和buffer占用的内存可以被快速回收,所以通常FO[3][3]比FO[2][3]会大很多。

    这里还用两个等式:

    • FO[3][2] = FO[2][2] - FO[2][5] - FO[2][6]
    • FO[3][3] = FO[2][3] + FO[2][5] + FO[2][6]

    这二者都不难理解。

      free命令由procps.*.rpm提供(在Redhat系列的OS上)。free命令的所有输出值都是从/proc/meminfo中读出的。

    在系统上可能有meminfo(2)这个函数,它就是为了解析/proc/meminfo的。procps这个包自己实现了meminfo()这个函数。可以下载一个procps的tar包看看具体实现,现在最新版式3.2.8。

    转载自:
    http://pczou.bokee.com/5944730.html
    http://hi.baidu.com/shlongli/blog/item/5a244009ae1465cc3bc76322.html

    进程的内存使用解析

                                          

    进程XXX占用了多少内存?这是个经常被问到,也经常被答错的问题。Linux进程的内存分配是个比较复杂的话题,而Linux上的工具往往把这个问题过分简单化,因此引出不少误解和困惑。首先把ps, top这类工具扔掉,然后看这么一个简单程序:

    [root@pczou pczou]# cat ./prog.c
    #i nclude <stdio.h>
    #i nclude <stdio.h>
    #i nclude <sys/types.h>
    #i nclude <unistd.h>

    #define ONEM (1024*1024)

    int func()
    {
            char s[16*ONEM];
            char* p;
            p = malloc(32*ONEM);
            pause();
            return 0;
    }

    int main()
    {
            printf("pid: %d\n", getpid());
            func();
            return 0;
    }


    其中func()这个函数分配了32MB的内存,以及16MB的堆栈。

    运行一下这个prog程序,prog会停在pause()的位置,看看ps怎么说:

    USER       PID %CPU %MEM   VSZ RSS TTY      STAT START   TIME COMMAND
    root      4238 0.0 0.0 52396 352 pts/0    S    21:29   0:00 ./prog

    VSZ指的是进程内存空间的大小,这里是52396KB;
    RSS指的是驻留物理内存中的内存大小,这里是352KB。

    一般系统管理员知道VSZ并不代表进程真正用到的内存,因为有些空间会仅在页表中挂个名,也就是说只是虚拟存在着,只有真正用到的时候内核才会把虚拟页面和真正的物理页面映射起来。比如,prog.c中用malloc()分配的32MB内存,由于程序中并没有用到这些内存,没有物理内存被分配,也就不应算到进程的帐上。

    进程的内存使用情况比较复杂,这是因为:

    • 进程所申请的内存不一定真正会被用到
    • 真正用到了的内存也不一定是只有该进程自己在用 (比如动态共享库)


    所以酒足饭饱结帐的时候,饭馆打出的帐单中往往漏洞百出,不是计入了没上的菜,就是一个菜算了两份钱。而ps给出的就是这样的“糊涂”帐单,不足为凭。

    算清楚帐的唯一办法是把每个菜都仔细过一遍,看看有没有上,有没有重复。下面的帐单要清楚多了:

    Virtual memory :     52396 KB
    Effective VM    :     52120 KB
    Mapped          :    352 KB
    Effective mapped:     76.6 KB
    Sole use        :     72 KB

    Per file memory use
    ld-2.3.4.so                   : VM   94208 B, M   90112 B, S    8192 B
    prog                          : VM    8192 B, M    8192 B, S    8192 B
    libc-2.3.4.so                 : VM    1180 KB, M 221184 B, S   16384 B


    可以看出,虽然虚拟地址空间是52396KB,实际映射(a.k.a. 分配)的空间是352KB,这和ps给出的结果一致。再看"Effective Mapped"这个值,仅为76.6 KB。这个值的计算方法是:

    有效的实际使用内存 = 该进程独占的内存 + 共享的内存A /共享A的进程数目 + 共享的内存B /共享B的进程数目 + ...

    比如对于一个kde应用程序kontact,它用的Qt库的虚拟地址空间为7M,而实际映射的空间有4.5M,也就是说真正给 Qt分配物理内存大小为4.5M。假设有10个KDE应用正在运行,那么记到kontact帐上的就不应该是4.5M,而是A-A之后的0.45M。这么算帐虽然并不十分准确,但"Effective Mapped"已经足以说明进程所占用内存的实际大小了。

    OK,最后用这个方法给系统中所有进程都“结下帐”:



    从上面的统计结果可以看出:

    • 虽然firefox的占用虚拟空间是最大的,但其实际占用的内存却比X Server要少。
    • firefox 的实际占用的内存和其RSS (a.k.a. mapped)差别不大,占RSS的99%;而kontact的实际占用内存却仅占RSS的63%,有27%的内存是共享的。由此可以粗略看出我用的窗口管理器是KDE而非Gnome,why? 因为Qt之类的共享库被很多KDE进程分担了。
    • sole值可以理解为"private mapped",也就是这个进程退出后可能被释放的内存 (对于非匿名的映射页面可能还会存留一段时间)。


    参考资料:

    • http://blog.zhaoke.com/31.html
    • http://www.berthels.co.uk/exmap/
    • http://projects.o-hand.com/#misc
    • smaps


    原文见:http://docs.google.com/View?docid=acqszgd2zwsk_18gzv8dk

     
     

    先介绍几个基本概念:

    SIZE: 进程使用的地址空间, 如果进程映射了100M的内存, 进程的地址空间将报告为100M内存. 事实上, 这个大小不是一个程序实际使用的内存数.

    RSS: "Resident Set Size", 实际驻留"在内存中"的内存数. 不包括已经交换出去的代码. 举一个例子: 如果你有一个程序使用了100K内存, 操作系统交换出40K内存, 那么RSS为60K. RSS还包括了与其它进程共享的内存区域. 这些区域通常用于libc库等.

    SHARE: RSS中与其它进程共享的内存部分大小.

    VMSIZE: 一个进程占用的总的地址空间大小. 它包括了没有映射到内存中的页面.

    Private RSS: 映射到内存中的页面, 这些页面仅由进程单独使用. 这也是我们最关心地方: 进程实际占用的内存数.

    如何来查看Private RSS呢? /proc接口中每一个进程目录下的smaps提供了private rss信息. smaps是在2.6.16内核版本引进来的.

    私有驻留内存数(Private RSS):
    查看/proc/$pid/smaps

    下面我以本站使用的Fedora Core 5为例, 查看进程号1293(vmware-guestd, 本站使用的是一台基于vmware的客户虚拟机, 微睦独立主机)使用的Private RSS数.

    CODE:
    # cat /proc/1293/smaps
    00111000-00112000 rwxp 00111000 00:00 0
    Size: 4 kB
    Rss: 4 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 4 kB
    0050e000-0050f000 rwxp 0050e000 00:00 0
    Size: 4 kB
    Rss: 0 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 0 kB
    0051a000-0051b000 r-xp 0051a000 00:00 0 [vdso]
    Size: 4 kB
    Rss: 4 kB
    Shared_Clean: 4 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 0 kB
    0051b000-00534000 r-xp 00000000 fd:00 194898 /lib/ld-2.4.so
    Size: 100 kB
    Rss: 0 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 0 kB
    00534000-00535000 r-xp 00018000 fd:00 194898 /lib/ld-2.4.so
    Size: 4 kB
    Rss: 0 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 0 kB
    00535000-00536000 rwxp 00019000 fd:00 194898 /lib/ld-2.4.so
    Size: 4 kB
    Rss: 0 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 0 kB
    00538000-00665000 r-xp 00000000 fd:00 194905 /lib/libc-2.4.so
    Size: 1204 kB
    Rss: 212 kB
    Shared_Clean: 204 kB
    Shared_Dirty: 0 kB
    Private_Clean: 8 kB
    Private_Dirty: 0 kB
    00665000-00667000 r-xp 0012d000 fd:00 194905 /lib/libc-2.4.so
    Size: 8 kB
    Rss: 8 kB
    Shared_Clean: 4 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 4 kB
    00667000-00668000 rwxp 0012f000 fd:00 194905 /lib/libc-2.4.so
    Size: 4 kB
    Rss: 4 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 4 kB
    00668000-0066b000 rwxp 00668000 00:00 0
    Size: 12 kB
    Rss: 8 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 8 kB
    08047000-08062000 r-xp 00000000 fd:00 292327 /usr/sbin/vmware-guestd
    Size: 108 kB
    Rss: 64 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 64 kB
    Private_Dirty: 0 kB
    08062000-08063000 rwxp 0001a000 fd:00 292327 /usr/sbin/vmware-guestd
    Size: 4 kB
    Rss: 4 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 4 kB
    08063000-08068000 rwxp 08063000 00:00 0
    Size: 20 kB
    Rss: 12 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 12 kB
    08385000-08886000 rwxp 08385000 00:00 0 [heap]
    Size: 5124 kB
    Rss: 5080 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 5080 kB
    bfeb2000-bfec7000 rwxp bfeb2000 00:00 0 [stack]
    Size: 84 kB
    Rss: 12 kB
    Shared_Clean: 0 kB
    Shared_Dirty: 0 kB
    Private_Clean: 0 kB
    Private_Dirty: 12 kB

    上面我们看到从smaps看不太方便, 推荐使用Ben Maurer写的perl脚本: (本地下载)

    下面是由seme.pl脚本解析的smaps数据:

    首先安装Linux::Smaps模块:
    perl -MCPAN -e 'install Linux::Smaps'

    然后用seme.pl解析1293进程的Smaps数据:

    CODE:
    # ./smem.pl 1293
    VMSIZE: 7200 kb
    RSS: 1052 kb total
    192 kb shared
    100 kb private clean
    760 kb private dirty
    PRIVATE MAPPINGS
    vmsize rss clean rss dirty file
    5636 kb 8 kb 724 kb [heap]
    84 kb 0 kb 12 kb [stack]
    4 kb 0 kb 4 kb
    8 kb 0 kb 4 kb /lib/libc-2.4.so
    4 kb 0 kb 4 kb /lib/libc-2.4.so
    12 kb 4 kb 4 kb
    4 kb 0 kb 4 kb /usr/sbin/vmware-guestd
    20 kb 8 kb 4 kb
    1204 kb 16 kb 0 kb /lib/libc-2.4.so
    108 kb 64 kb 0 kb /usr/sbin/vmware-guestd

    SHARED MAPPINGS
    vmsize rss clean rss dirty file
    1204 kb 188 kb 0 kb /lib/libc-2.4.so
    4 kb 4 kb 0 kb [vdso]

    从上面看到rss大小被分成了两个部分: private(私有)和shared(共享).
    private rss就是我们最关心的进程实际占用的内存数.

    参考:
    1.
    Ben Maurer's smem.pl script
    2. smaps and maps, also proc man pages.
    3.
    如何查看进程在内存中分配的地址范围?

    Linux中/proc/[pid]/status详细说明

    关键字: linux

    [root@localhost ~]# cat /proc/self/status
    Name: cat
    State: R (running)
    SleepAVG: 88%
    Tgid: 5783
    Pid: 5783
    PPid: 5742
    TracerPid: 0
    Uid: 0 0 0 0
    Gid: 0 0 0 0
    FDSize: 256
    Groups: 0 1 2 3 4 6 10
    VmSize: 6588 kB
    VmLck: 0 kB
    VmRSS: 400 kB
    VmData: 144 kB
    VmStk: 2040 kB
    VmExe: 14 kB
    VmLib: 1250 kB
    StaBrk: 0804e000 kB
    Brk: 088df000 kB
    StaStk: bfe03270 kB
    ExecLim: 0804c000
    Threads: 1
    SigPnd: 0000000000000000
    ShdPnd: 0000000000000000
    SigBlk: 0000000000000000
    SigIgn: 0000000000000000
    SigCgt: 0000000000000000
    CapInh: 0000000000000000
    CapPrm: 00000000fffffeff
    CapEff: 00000000fffffeff


    输出解释
    参数 解释
    Name 应用程序或命令的名字
    State 任务的状态,运行/睡眠/僵死/
    SleepAVG 任务的平均等待时间(以nanosecond为单位),交互式任务因为休眠次数多、时间长,它们的 sleep_avg 也会相应地更大一些,所以计算出来的优先级也会相应高一些。
    Tgid 线程组号
    Pid 任务ID
    Ppid 父进程ID
    TracerPid 接收跟踪该进程信息的进程的ID号
    Uid Uid euid suid fsuid
    Gid Gid egid sgid fsgid
    FDSize 文件描述符的最大个数,file->fds
    Groups
    VmSize(KB) 任务虚拟地址空间的大小 (total_vm-reserved_vm),其中total_vm为进程的地址空间的大小,reserved_vm:进程在预留或特殊的内存间的物理页
    VmLck(KB) 任务已经锁住的物理内存的大小。锁住的物理内存不能交换到硬盘 (locked_vm)
    VmRSS(KB) 应用程序正在使用的物理内存的大小,就是用ps命令的参数rss的值 (rss)
    VmData(KB) 程序数据段的大小(所占虚拟内存的大小),存放初始化了的数据; (total_vm-shared_vm-stack_vm)
    VmStk(KB) 任务在用户态的栈的大小 (stack_vm)
    VmExe(KB) 程序所拥有的可执行虚拟内存的大小,代码段,不包括任务使用的库 (end_code-start_code)
    VmLib(KB) 被映像到任务的虚拟内存空间的库的大小 (exec_lib)
    VmPTE 该进程的所有页表的大小,单位:kb
    Threads 共享使用该信号描述符的任务的个数,在POSIX多线程序应用程序中,线程组中的所有线程使用同一个信号描述符。
    SigQ 待处理信号的个数
    SigPnd 屏蔽位,存储了该线程的待处理信号
    ShdPnd 屏蔽位,存储了该线程组的待处理信号
    SigBlk 存放被阻塞的信号
    SigIgn 存放被忽略的信号
    SigCgt 存放被俘获到的信号
    CapInh Inheritable,能被当前进程执行的程序的继承的能力
    CapPrm Permitted,进程能够使用的能力,可以包含CapEff中没有的能力,这些能力是被进程自己临时放弃的,CapEff是CapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性
    CapEff Effective,进程的有效能力
  • 相关阅读:
    maven命令
    一个Maven项目在eclipse中正常,但在IDEA中启动时报错
    idea导入eclipse的普通web项目
    idea启动慢的解决办法
    如何在idea里切换项目不同分支
    定时任务
    springboot项目打成war包
    springboot配置信息
    Controller层方法传参和返回字符串
    [C#学习] popupControlContainer控件
  • 原文地址:https://www.cnblogs.com/zhangzhang/p/2458820.html
Copyright © 2020-2023  润新知