Know Your Working Environment - Memory

@ 2011-07-12 21:31:52
标签:

    系统的计算资源主要体现在两个方面,CPU和Memory。了解系统或进程的内存使用情况在工作中是经常需要的。

    系统的内存使用情况

    top

    top是常用的用来查看系统或进程状态的命令。

    top - 06:19:16 up 109 days, 12:26, 83 users,  load average: 0.88, 0.68, 0.58
    Tasks: 296 total,   1 running, 295 sleeping,   0 stopped,   0 zombie
    Cpu(s):  3.8% us,  0.2% sy,  0.0% ni, 95.9% id,  0.1% wa,  0.0% hi,  0.0% si
    Mem:  49454280k total, 33299392k used, 16154888k free,   280616k buffers
    Swap: 83883388k total,   176672k used, 83706716k free, 21073420k cached
    
      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND 
        1 root      16   0  4768  404  372 S  0.0  0.0   0:07.32 init  
    ... ...                                                                         
    

    free

    free很适合用来查看系统的可用内存大小。

    $ free -m
                 total       used       free     shared    buffers     cached
    Mem:         48295      32526      15768          0        274      20586
    -/+ buffers/cache:      11666      36629
    Swap:        81917        172      81744
    

    这里需要说明的是 “-/+ buffers/cache”行。在一行中,"used"和"free"列分别减去和加上了buffers/cached列的值。

    buffers/cached 可能会占用系统内存,但不是必须的。系统在需要时可以收回这部分内存,因而可以算作是空闲(free)内存的一部分。

    buffers & cached

    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.

    缓存(cached)是把读取过的数据保存起来,重新读取时若命中(找到需要的数据)就不要去读硬盘了,若没有命中就读硬盘。其中的数据会根据读取频率进行组织,把最频繁读取的内容放在最容易找到的位置,把不再读的内容不断往后排,直至从中删除。

    缓冲(buffers)是根据磁盘的读写设计的,把分散的写操作集中进行,减少磁盘碎片和硬盘的反复寻道,从而提高系统性能。

    为了提高性能,操作系统会尽量使用空闲的内存作为buffers或cached。但这些buffers或cached在需要时是可以被其他程序使用的。

    如何清空cached/buffers

    一种办法是"Drop Caches",写入一个数字到文件 "/proc/sys/vm/drop_caches".

    sync                                ; # flash cache to disk
    echo 3 > /proc/sys/vm/drop_caches   ; # 清空 cached/buffers
    

    另一种办法是写个程序,消耗内存,直到cached/buffers占用的空间被系统释放。下面的程序引自 Experiments and fun with the Linux disk cache

    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    
    int main(int argc, char** argv) {
        int max = -1;
        int mb = 0;
        char* buffer;
    
        if(argc > 1) max = atoi(argv[1]);
    
        while((buffer=malloc(1024*1024)) != NULL && mb <= max) {
            memset(buffer, 0, 1024*1024);
            printf("Allocated %d MB\n", mb++);
        }
        return 0;
    }
    

    进程的内存使用情况

    /proc/$pid/status

    文件 /proc/$pid/status中包含对应进程的内存使用情况。

    $ awk '/^Vm/ {printf "%s %8.1f page\n",$0, $2/4}' /proc/$pid/status
    VmSize:    54236 kB  13559.0 page  # 进程的虚拟内存的大小  
    VmLck:         0 kB      0.0 page  # 加锁的虚拟内存大小
    VmRSS:      1972 kB    493.0 page  # 使用的物理内存的大小 
    VmData:     1156 kB    289.0 page  # 程序数据段大小 (Heap)
    VmStk:       212 kB     53.0 page  # 栈的大小      (Stack) 
    VmExe:       318 kB     79.5 page  # 可执行占用的虚拟内存大小
    VmLib:      1342 kB    335.5 page  # 动态链接库占用的虚拟内存大小
    

    /proc/$pid/statm

    文件/proc/$pid/statm从另一个角度反映进程的内存使用情况。

    $ cat /proc/20164/statm
    13559 493 246 79 0 342 0
    
    # 显示的7个数值单位都是页(page),每页的大小通常是4KB。
    # 7个数值分别表示
    #  1. VmSize       : 进程虚拟内存空间的大小 
    #  2. VmRSS        : 占用的物理内存大小
    #  3. VmShared     : 共享的页的大小
    #  4. VmExe        : 程序代码占用的空间大小
    #  5. VmLib        : 被映像倒任务的虚拟内存空间的库的大小 (不等同于VmLib) 
    #  6. VmData+VmStk : 程序数据段和用户态的栈的大小  
    #  7. Dirty Pages  : 脏页数量 
    

    /proc/$pid/maps

    文件/proc/$pid/maps列出了里程的虚拟内存的映射表。
    文件/proc/$pid/smaps除了包含/proc/$pid/maps内容之外,还多了些虚拟内存的使用情况数据。
    虚拟内存映射表每行有6列:

    1. 第一列:内存段的虚拟地址
    2. 第二列:内存段的执行权限,r、w、x、p(私有)、s(共享)
      • 理论上,heap和stack段不应该有x权限
    3. 第三列:代表在进程地址里的偏移量
    4. 第四列:映像文件的主设备号和次设备号(16进制)
    5. 第五列:映像文件的节点号,即inode值。0表示没有对应的文件。
    6. 第六列:映像文件的路径
    $ cat /proc/$pid/maps
    00400000-00450000     r-xp 00000000 68:01 4948064   /bin/tcsh
    0054f000-00554000     rw-p 0004f000 68:01 4948064   /bin/tcsh
    00554000-0063f000     rwxp 00554000 00:00 0 
    2a95556000-2a9556b000 r-xp 00000000 68:01 5079045   /lib64/ld-2.3.4.so
    
    $ cat /proc/$pid/smaps
    00400000-00450000     r-xp 00000000 68:01 4948064   /bin/tcsh
    Size:               320 kB
    Rss:                284 kB
    Shared_Clean:       284 kB
    Shared_Dirty:         0 kB
    Private_Clean:        0 kB
    Private_Dirty:        0 kB
    
    # 可以根据 smaps文件做汇总计算
    
    $ awk -f mem.awk /proc/$pid/smaps
    VmSize :    54240    13560
    VmRss  :     1972      493
    Shared :      992      248
    Private:      980      245
    Dirty  :        0        0
    

    上面提到的"mem.awk"文件的内容如下:

    /^(Size|Rss|Shared|Private)/ {sum[$1]+=$2} 
    
    END{
      sum_shared  = sum["Shared_Clean:"]+sum["Shared_Dirty:"]; 
      sum_private = sum["Private_Clean"]+sum["Private_Dirty:"]; 
      sum_dirty   = sum["Shared_Dirty"]+sum["Private_Dirty"];
    
      printf "VmSize : %8d %8d\n", sum["Size:"], sum["Size:"]/4;
      printf "VmRss  : %8d %8d\n", sum["Rss:"],  sum["Rss:"]/4;
      printf "Shared : %8d %8d\n", sum_shared,  sum_shared/4;
      printf "Private: %8d %8d\n", sum_private, sum_private/4;
      printf "Dirty  : %8d %8d\n", sum_Dirty,   sum_Dirty/4;
    }
    

    参考资料

    标签:

      分享到:
      comments powered by Disqus

      42/46ms