Linux下内存使用分析思路

在系统层面最基础最重要的三个指标是CPU、IO、memory,本篇主要汇总定位分析内存使用的常见思路。在进行下一步之前,需要先对top、free 、/proc/meminfo、slabtop、nmon等工具要有一个概念和认识。如果可能的话,最好还需要先了解下/proc/$pid下的smaps和status文件。以下为定位内存被谁占用的常见思路。

一、free和top

free命令是linux的一个入门级命令,显示的是一个比较总述性的信息,如下:

 
 
  1. [root@361way ~]# free -m
  2. total used free shared buffers cached
  3. Mem: 995 874 121 0 105 249
  4. -/+ buffers/cache: 518 477
  5. Swap: 0 0 0

比如上面的输出中,我们大致可以看到我总内存为1G(995,其中hardward和firmware在启动时会预先占用一点)。其中已使用874M ,其中可用121M,buffers和cached加用的量为105M + 249M ,这里需要注意的是平时我们在查看时,一般会以第二行的结果为准,即实际可用477M,已用518M。为什么这样说?因为buffers和cached是为了加快运算速度,会预占用一部分内存,可以理解为缓存的概念。由于这部分不是本篇的重点,想深究的可以找谷歌。这部分内存可以通过如下的命令进行回收:

 
 
  1. To free pagecache:
  2. echo 1 > /proc/sys/vm/drop_caches
  3. To free dentries and inodes:
  4. echo 2 > /proc/sys/vm/drop_caches
  5. To free pagecache, dentries and inodes:
  6. echo 3 > /proc/sys/vm/drop_caches

在有业务运行的情况下,强烈不建议这样操作,因为可能会造成数据丢失

即然内存被使用,到底被谁占去了呢?可以借助强大的top查看。

top memory

如上图所示,在top下我们输入大M就可以按内存使用率排序。上面可以看到我内存主要被hhvm进程占用掉了,占比总内存的34.3% 。可以看到,实际上top上面也有free的功能,对memory会有概述性报告的。其中RES是我们要关注的项,即实际该进程占用的内存量,基本上这样我们就定位到内存用到那去了。现网中经常还需要一种情况,top看到的所有进程的RES使用都不大,而内存一下子少了几十G,这个怎么破呢?看下面。

二、nmon 、/proc/meminfo 与slabtop

1、/proc/meminfo

meminfo文件显示出的也是内存的概述性信息,只不过其比free -m的结果要更详细,如下:

 
 
  1. [root@361way ~]# cat /proc/meminfo
  2. MemTotal: 1019644 kB 所有可用RAM大小 (即物理内存减去一些预留位和内核的二进
  3. 制代码大小)
  4. MemFree: 119464 kB LowFreeHighFree的总和,被系统留着未使用的内存
  5. Buffers: 110680 kB 用来给文件做缓冲大小
  6. Cached: 256796 kB 被高速缓冲存储器(cache memory)用的内存的大小(等于
  7. diskcache + SwapCache
  8. SwapCached: 0 kB   
  9. Active: 680560 kB  在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非
  10. 非常必要否则不会被移作他用
  11. Inactive: 145228 kB 在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可
  12. 能被用于其他途径
  13. Active(anon): 458208 kB
  14. Inactive(anon): 280 kB
  15. Active(file): 222352 kB
  16. Inactive(file): 144948 kB
  17. Unevictable: 0 kB
  18. Mlocked: 0 kB
  19. SwapTotal: 0 kB
  20. SwapFree: 0 kB
  21. Dirty: 92 kB 等待被写回到磁盘的内存大小
  22. Writeback: 0 kB 正在被写回到磁盘的内存大小
  23. AnonPages: 458328 kB 未映射页的内存大小
  24. Mapped: 27072 kB 设备和文件等映射的大小
  25. Shmem: 176 kB
  26. Slab: 53564 kB 内核数据结构缓存的大小,可以减少申请和释放内存带来的消耗
  27. SReclaimable: 32404 kB 可收回Slab的大小
  28. SUnreclaim: 21160 kB 不可收回Slab的大小(SUnreclaim+SReclaimableSlab
  29. KernelStack: 1136 kB 内核栈大小占用的内存
  30. PageTables: 5856 kB 管理内存分页页面的索引表的大小
  31. NFS_Unstable: 0 kB 不稳定页表的大小
  32. Bounce: 0 kB
  33. WritebackTmp: 0 kB
  34. CommitLimit: 509820 kB
  35. Committed_AS: 1483868 kB
  36. VmallocTotal: 34359738367 kB 可以vmalloc虚拟内存大小
  37. VmallocUsed: 7472 kB 已经被使用的虚拟内存大小
  38. VmallocChunk: 34359728764 kB
  39. HardwareCorrupted: 0 kB
  40. AnonHugePages: 198656 kB
  41. HugePages_Total: 0
  42. HugePages_Free: 0
  43. HugePages_Rsvd: 0
  44. HugePages_Surp: 0
  45. Hugepagesize: 2048 kB
  46. DirectMap4k: 7168 kB
  47. DirectMap2M: 1044480 kB

可以看到上面的内存具体用途显示的特别详细,有点像饭店或超市的帐单。其中有几个我们经常接触到的有buffer 、cached 、slab、hugepage、vmall 。前两者就不说了,slab后面也会单独提到,hugepage是为了加快IO处理的速度设置的一个调优项,在数据库、虚拟化上经常会调节该部分,也会出现该部分占用较大的情况。vmall 是一个些许专业的概念,具体可以参看百科csdn上的介绍。该值我们可以在内核启动时vmalloc=xxx来指定。由于这部分显示的要远大于物理内存,平时我们时关注VmallocUsed一项即可。

所以针对上面提到的进程本身占用都不多,而free -m 确发现已用几十G的情况,就可以在这里查看到具体是那一项占的高,很可能是hugepage或slab 。

2、nmon

/proc/meminfo显示的结果非常详细也非常直观,不过我们平时关心的主要就那几个,而且显示如此多,很多一些重要的东西就忽略掉了,这里可以借助IBM出的工具nmon来查看内存分配情况。如下图:

IBM nmon memory

从上面这个输出,也可以看到主要内存还是被active占用的。其次是cached和buffers 。其他几块并没有占用多少内存。

注意:SecureCRT下nmon会有乱码出现,通过将终端类型修改为vt100并重连就OK了。

3、slabtop

内核的模块在分配资源的时候,为了提高效率和资源的利用率,都是透过slab来分配的。slab为结构性缓存占用内存,该项也经常占用很大的内存。不过借助slabtop工具,我们可以很方便的显示内核片缓存信息,该工具可以更直观的显示/proc/slabinfo下的内容。理解意思就行,如下图:

slabtop memory

如上图所示,objs是指对象的个数,obj_size为对象的大小,use是使用的百分比,这个百分比是针对后面的cache_size来说的。cache_size是给kmem_cache所有对象分配的总大小。我们可以将slabtop查看到的结果与/proc/slabinfo的结果做一个对比,如下,其中/proc/slabinfo中的第三列与第四列的值为num_objs和objsize。这里通过slabtop取得的cache_size乘百分比得到的结果和/proc/slabinfo 3、4列乘积求和得到的结果基本相同。

 
 
  1. [root@361way 01]# slabtop -o|column -t|grep ^[0-9]|awk 'BEGIN{sum=0;}{sum=sum+int($(NF-1)*int($3));}END{print sum/1024/100}'
  2. 49.4671
  3. [root@361way 01]# cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'
  4. 51.9877

同样,在对slabtop不乘百分比时求和与/proc/meminfo里slab项得到的值也基本相同:

 
 
  1. [root@361way 01]# slabtop -o|column -t|grep ^[0-9]|awk 'BEGIN{sum=0;}{sum=sum+int($(NF-1));}END{print sum/1024}'
  2. 54.0898

所以我们也可以通过/proc/slabinfo获取占用内存大于100M的对象集:

 
 
  1. # cat /proc/slabinfo |awk '{if($3*$4/1024/1024 > 100){print $1,$3*$4/1024/1024} }'
  2. ext3_inode_cache 282.575
  3. proc_inode_cache 2154.03
  4. dentry_cache 868.075

如上面的结果,可以看到发现proc_inode这个占了2G多。是占比较多的。

三、进程内存及其他

和内存相关的虚拟文件还有如下这些,其中我们比较重点关注的是smaps和status文件,smem工具就是就是根据这些文件进行的统计分析与处理,具体可以参看我的另一篇博文---linux用smem分析内存占用情况 。

 
 
  1. /proc/$pid/cmdline
  2. /proc/$pid/smaps 详细的内存占用情况
  3. /proc/$pid/status 详细的内存占用情况
  4. /proc/$pid/maps
  5. /proc/$pid/stat
  6. /proc/meminfo

这里我们以hhvm 程序的内存为例,这两个文件的内容如下:

 
 
  1. [root@361way 01]# cat /proc/22186/smaps |more //内存使用的分类明细
  2. 00400000-02335000 r-xp 00000000 ca:01 1073823 /usr/bin/hhvm
  3. Size: 31956 kB
  4. Rss: 30496 kB
  5. Pss: 30494 kB
  6. Shared_Clean: 4 kB
  7. Shared_Dirty: 0 kB
  8. Private_Clean: 30492 kB
  9. Private_Dirty: 0 kB
  10. Referenced: 8136 kB
  11. Anonymous: 0 kB
  12. AnonHugePages: 0 kB
  13. Swap: 0 kB
  14. KernelPageSize: 4 kB
  15. MMUPageSize: 4 kB
  16. 02534000-025b8000 rwxp 01f34000 ca:01 1073823 /usr/bin/hhvm
  17. Size: 528 kB
  18. Rss: 452 kB
  19. Pss: 450 kB
  20. Shared_Clean: 4 kB
  21. Shared_Dirty: 0 kB
  22. Private_Clean: 364 kB
  23. Private_Dirty: 84 kB
  24. Referenced: 100 kB
  25. Anonymous: 84 kB
  26. AnonHugePages: 0 kB
  27. Swap: 0 kB
  28. KernelPageSize: 4 kB
  29. MMUPageSize: 4 kB
  30. 025b8000-02603000 rwxp 00000000 00:00 0
  31. Size: 300 kB
  32. Rss: 252 kB
  33. Pss: 252 kB
  34. Shared_Clean: 0 kB
  35. Shared_Dirty: 0 kB
  36. Private_Clean: 0 kB
  37. Private_Dirty: 252 kB
  38. Referenced: 164 kB
  39. Anonymous: 252 kB
  40. AnonHugePages: 0 kB
  41. Swap: 0 kB
  42. KernelPageSize: 4 kB
  43. MMUPageSize: 4 kB
  44. 029b7000-02c39000 rwxp 01fb7000 ca:01 1073823 /usr/bin/hhvm
  45. Size: 2568 kB
  46. Rss: 8 kB
  47. Pss: 8 kB
  48. [root@361way 01]# cat /proc/22186/status //本进程的内存使用概述
  49. Name: hhvm
  50. State: S (sleeping)
  51. Tgid: 22186
  52. Pid: 22186
  53. PPid: 1
  54. TracerPid: 0
  55. Uid: 500 500 500 500
  56. Gid: 500 500 500 500
  57. Utrace: 0
  58. FDSize: 64
  59. Groups: 500
  60. VmPeak: 1198068 kB
  61. VmSize: 1198064 kB
  62. VmLck: 0 kB
  63. VmHWM: 369216 kB
  64. VmRSS: 318504 kB
  65. VmData: 772992 kB
  66. VmStk: 88 kB
  67. VmExe: 31956 kB
  68. VmLib: 144840 kB
  69. VmPTE: 1688 kB
  70. VmSwap: 0 kB
  71. Threads: 4
  72. SigQ: 2/7789
  73. SigPnd: 0000000000000000
  74. ShdPnd: 0000000000000000
  75. SigBlk: 0000000000000000
  76. SigIgn: 0000000000001000
  77. SigCgt: 0000000182006eed
  78. CapInh: 0000000000000000
  79. CapPrm: 0000000001800400
  80. CapEff: 0000000001800400
  81. CapBnd: ffffffffffffffff
  82. Cpus_allowed: 7fff
  83. Cpus_allowed_list: 0-14
  84. Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001
  85. Mems_allowed_list: 0
  86. voluntary_ctxt_switches: 492
  87. nonvoluntary_ctxt_switches: 194

常见的内存分析手段和工具基本上就上面这些,如果想和更深一步的了解内存在kernel 中的分配原理,可以参看如下内存管理页面:

Linux Memory Management

Memory Management

Linux 内存管理

猜你喜欢

转载自blog.csdn.net/odeng888/article/details/80062544