深入分析linux内存使用的情况详解

昝辉Zac Zac的SEO博客,坚持12年,优化成为生活。

有朋友发现有台128的内存结果发现在使用时有点不对了,下面小编整理了一篇关于linux内存去哪儿了问题解决办法吧.

前两天一台128G内存的oracle主机发生故障触发kdump,最终由于var目录空间不足,导致kdump生成不完全,结合之前redhat给出的建议,crash设置的空间最好大于memory 空间,对此我们做了一个简单的计算,认为kdump主机生成的是运行在内存里的信息,虽然主机有128G的内存,不过通过top查看并计算后发现我实际上只使用7G多的大小,而使用free -m查看时已经使用了80G左右的内存,站在DBA的角度看的话,这部分内存提前分配给了sga,貌似也可以讲通,记得之前看过taobao褚霸写的一篇分析,这里再结合该文章算算.

通过褚霸的Linux Used内存到底哪里去了?我们已经了解到内存主要消耗在三个方面:

1.进程消耗

2.slab消耗

3.pagetable消耗

由于不便于直接在现网oracle主机上进行操作,这里就以本blog的云主机为例进行测试.

一、查看已用内存总量

  1. [root@91it~]#free-m
  2. totalusedfreesharedbufferscached
  3. Mem:996908880174283
  4. -/+buffers/cache:450546
  5. Swap:000

于已用内存和可用内存这已经是一个老生长谈的问题了,这里看到的信息如下.

1、总内存996M,已用内存908M

2、由于buffers + cached内存实际上也是可用内存,该内存也可以通过echo 3 > /proc/sys/vm/drop_caches 回收pagechae、dentries and inodes,所以实际上已经使用的内存是450M.

注:1、关于内存的计算方法就不上图了,这点可以参考:http://www.redbooks.ibm.com/redpapers/pdfs/redp4285.pdf

2、linux内存强制回收的方法具体可以参考:linux 下 强制回收内存.

即然实际使用了450M内存,那这450M内存是如何分配的呢?

二、RSS内存(Resident size)

ps下命令下的RSS内存、top工具下的RES内存都是指的这一块内存,resident set size 也就是每个进程用了具体的多少页的内存,由于linux系统采用的是虚拟内存,进程的代码,库,堆和栈使用的内存都会消耗内存,但是申请出来的内存,只要没真正touch过,是不算的,因为没有真正为之分配物理页面,说白了也就是真正具有“数据页的物理内存”,我这里使用的是一段从python psutil 模块里演化出的一段代码进行计算的:

  1. [root@91it~]#catvms.py
  2. #!/usr/bin/python
  3. importos
  4. defget_vms(pid):
  5. withopen("/proc/%s/statm"%pid,"rb")asf:
  6. vms=f.readline().split()[1]
  7. returnint(vms)
  8. pids=[int(x)forxinos.listdir(b'/proc')ifx.isdigit()]
  9. vmss=[get_vms(pid)forpidinpids]
  10. printsum(vmss)*4
  11. [root@91it~]#pythonvms.py
  12. 386528

注:1、/proc/PID/statm 第二列是RSS内存使用page页的多少,而在linux下默认使用的page页大小是4KB,所以我上面计算求和后,最后乘以4,而我最终计算出的结果就是386528KB.

2、这里也可以通过/proc/PID/status里的vmRss项进行求和,因为该项直接给出的是KB值.

  1. [root@91it~]#cat/proc/998/status
  2. Name:mingetty
  3. State:S(sleeping)
  4. Tgid:998
  5. Pid:998
  6. PPid:1
  7. TracerPid:0
  8. Uid:0000
  9. Gid:0000
  10. Utrace:0
  11. FDSize:64
  12. Groups:
  13. VmPeak:4068kB
  14. VmSize:4064kB
  15. VmLck:0kB
  16. VmHWM:556kB
  17. VmRSS:76kB
  18. ………………………………

当然也可以使用shell 进行计算:

  1. $catRSS.sh
  2. #/bin/bash
  3. forPROCin`ls/proc/|grep"^[0-9]"`
  4. do
  5. if[-f/proc/$PROC/statm];then
  6. TEP=`cat/proc/$PROC/statm|awk'{print($2)}'`
  7. RSS=`expr$RSS+$TEP`
  8. fi
  9. done
  10. RSS=`expr$RSS*4`
  11. echo$RSS"KB"

rss内存部分,具体可以查看man proc手册或kernl 页的介绍,以下是man proc 里的部分提取:

  1. /proc/[pid]/statm
  2. Providesinformationaboutmemoryusage,measuredinpages.The
  3. columnsare:
  4. sizetotalprogramsize
  5. (sameasVmSizein/proc/[pid]/status)
  6. residentresidentsetsize
  7. (sameasVmRSSin/proc/[pid]/status)
  8. sharesharedpages(fromsharedmappings)
  9. texttext(code)
  10. liblibrary(unusedinLinux2.6)
  11. datadata+stack
  12. dtdirtypages(unusedinLinux2.6)

二、slab内存

slab内存的作用是内核为了高性能每个需要重复使用的对象都会有个池,这个slab池会cache大量常用的对象,所以会消耗大量的内存,具体可以运行slabtop命令查看.

slab内存的消耗我们可以通过/proc/slabinfo文件算出,具脚本为:

  1. #echo`cat/proc/slabinfo|awk'BEGIN{sum=0;}{sum=sum+$3*$4;}END{printsum/1024/1024}'`MB
  2. 74.7215MB

三、PageTables内存

这部分内存我并没有细研究,这里就直接拉taobao上各位大牛的说法用吧:“struct page也有一定的大小(每个页一个,64bytes),如果是2.6.32的话,每个页还有一个page_cgroup(32bytes),也就是说内存大小的2.3%(96/4096)会被内核固定使用,struct page是系统boot的时候就会根据内存大小算出来分配出去的,18内核是1.56%左右,32内核由于cgroup的原因会在2.3%.”

而具体消耗可以通过/proc/meminfo里的pagetables项获取,脚本如下:

  1. #echo`grepPageTables/proc/meminfo|awk'{print$2}'`KB
  2. 4476KB

系统的硬开销占比并不多.

四、算算总帐

三者加起来发现要大于450M,这里我们便于查看,再跑下脚本:

  1. $catcm.sh
  2. #/bin/bash
  3. forPROCin`ls/proc/|grep"^[0-9]"`
  4. do
  5. if[-f/proc/$PROC/statm];then
  6. TEP=`cat/proc/$PROC/statm|awk'{print($2)}'`
  7. RSS=`expr$RSS+$TEP`
  8. fi
  9. done
  10. RSS=`expr$RSS*4`
  11. PageTable=`grepPageTables/proc/meminfo|awk'{print$2}'`
  12. SlabInfo=`cat/proc/slabinfo|awk'BEGIN{sum=0;}{sum=sum+$3*$4;}END{printsum/1024/1024}'`
  13. echo$RSS"KB",$PageTable"KB",$SlabInfo"MB"
  14. printf"rss+pagetable+slabinfo=%sMBn"`echo$RSS/1024+$PageTable/1024+$SlabInfo|bc`//phpfensi.com
  15. free-m
  16. $./cm.sh
  17. 382048KB,4528KB,74.8561MB
  18. rss+pagetable+slabinfo=451.8561MB
  19. totalusedfreesharedbufferscached
  20. Mem:9968421540106376
  21. -/+buffers/cache:359637
  22. Swap:000

由于上面演示时,我强制回收过内存,目前实际已用内存为359M,而我们上面三者之和是451M,比实际使用的大了100M左右.

多出的这部分内存是我们在计算rss内存时算重复了,因为rss内存包括我们使用的各种库和so等共享的模块,具体可以使用pmap指令查看详细的每个进程调用的lib库及已用内存值,这里以最简单的bash进程为例.

  1. [root@91it~]#pmap`pgrepbash`
  2. 1464:-bash
  3. 0000000000400000848Kr-x--/bin/bash
  4. 00000000006d300040Krw---/bin/bash
  5. 00000000006dd00020Krw---[anon]
  6. 00000000008dc00036Krw---/bin/bash
  7. 00000000011a4000396Krw---[anon]
  8. 0000003ef9800000128Kr-x--/lib64/ld-2.12.so
  9. 0000003ef9a1f0004Kr----/lib64/ld-2.12.so
  10. 0000003ef9a200004Krw---/lib64/ld-2.12.so
  11. 0000003ef9a210004Krw---[anon]
  12. 0000003ef9c000001576Kr-x--/lib64/libc-2.12.so
  13. 0000003ef9d8a0002048K-----/lib64/libc-2.12.so
  14. 0000003ef9f8a00016Kr----/lib64/libc-2.12.so
  15. 0000003ef9f8e0004Krw---/lib64/libc-2.12.so
  16. 0000003ef9f8f00020Krw---[anon]
  17. 0000003efa4000008Kr-x--/lib64/libdl-2.12.so
  18. 0000003efa4020002048K-----/lib64/libdl-2.12.so
  19. 0000003efa6020004Kr----/lib64/libdl-2.12.so
  20. 0000003efa6030004Krw---/lib64/libdl-2.12.so
  21. 0000003efb800000116Kr-x--/lib64/libtinfo.so.5.7
  22. 0000003efb81d0002048K-----/lib64/libtinfo.so.5.7
  23. 0000003efba1d00016Krw---/lib64/libtinfo.so.5.7
  24. 00007f1a42fc800096836Kr----/usr/lib/locale/locale-archive
  25. 00007f1a48e5900048Kr-x--/lib64/libnss_files-2.12.so
  26. 00007f1a48e650002048K-----/lib64/libnss_files-2.12.so
  27. 00007f1a490650004Kr----/lib64/libnss_files-2.12.so
  28. 00007f1a490660004Krw---/lib64/libnss_files-2.12.so
  29. 00007f1a4906700012Krw---[anon]
  30. 00007f1a4906b0008Krw---[anon]
  31. 00007f1a4906d00028Kr--s-/usr/lib64/gconv/gconv-modules.cache
  32. 00007f1a490740004Krw---[anon]
  33. 00007fff4818900084Krw---[stack]
  34. 00007fff481ff0004Kr-x--[anon]
  35. ffffffffff6000004Kr-x--[anon]
  36. total108472K
  37. 2757:-bash
  38. 0000000000400000848Kr-x--/bin/bash
  39. 00000000006d300040Krw---/bin/bash
  40. 00000000006dd00020Krw---[anon]
  41. 00000000008dc00036Krw---/bin/bash
  42. 0000000001385000396Krw---[anon]
  43. 0000003ef9800000128Kr-x--/lib64/ld-2.12.so
  44. 0000003ef9a1f0004Kr----/lib64/ld-2.12.so
  45. 0000003ef9a200004Krw---/lib64/ld-2.12.so
  46. 0000003ef9a210004Krw---[anon]
  47. 0000003ef9c000001576Kr-x--/lib64/libc-2.12.so
  48. 0000003ef9d8a0002048K-----/lib64/libc-2.12.so
  49. 0000003ef9f8a00016Kr----/lib64/libc-2.12.so
  50. 0000003ef9f8e0004Krw---/lib64/libc-2.12.so
  51. 0000003ef9f8f00020Krw---[anon]
  52. 0000003efa4000008Kr-x--/lib64/libdl-2.12.so
  53. 0000003efa4020002048K-----/lib64/libdl-2.12.so
  54. 0000003efa6020004Kr----/lib64/libdl-2.12.so
  55. 0000003efa6030004Krw---/lib64/libdl-2.12.so
  56. 0000003efb800000116Kr-x--/lib64/libtinfo.so.5.7
  57. 0000003efb81d0002048K-----/lib64/libtinfo.so.5.7
  58. 0000003efba1d00016Krw---/lib64/libtinfo.so.5.7
  59. 00007fda04cb100096836Kr----/usr/lib/locale/locale-archive
  60. 00007fda0ab4200048Kr-x--/lib64/libnss_files-2.12.so
  61. 00007fda0ab4e0002048K-----/lib64/libnss_files-2.12.so
  62. 00007fda0ad4e0004Kr----/lib64/libnss_files-2.12.so
  63. 00007fda0ad4f0004Krw---/lib64/libnss_files-2.12.so
  64. 00007fda0ad5000012Krw---[anon]
  65. 00007fda0ad540008Krw---[anon]
  66. 00007fda0ad5600028Kr--s-/usr/lib64/gconv/gconv-modules.cache
  67. 00007fda0ad5d0004Krw---[anon]
  68. 00007fff0e9e000084Krw---[stack]
  69. 00007fff0e9ff0004Kr-x--[anon]
  70. ffffffffff6000004Kr-x--[anon]
  71. total108472K

从上面的指令上看出,pid为1464和2757两个进程使用很多相同的so文件,而且其内存地址也相同,这里个人认为rss部分的内存理论上是可以完全计算准确的,做法就是先遍历/proc下所有的pid,再pmap所有pid,对所有的输出结果进行汇总后去重,再将第二列的占用内存值求和,具体也可以考虑从/proc/pid/smaps文件入手.

五、其他情况

在第四步算算总帐中,我们看出 rrs内存 + slab内存 + pagetables内存 > 实际已用内存,但该情况并非是绝对的,也有例外,在我上面提到的oracle 使用场景下,事先分配了70g左右的oracle sga 空间(即内存空间),而三者相加要远远小于实际使用的物理内存,这又要怎么解释呢?再去除cache和buffer的空间也要远远小于实际使用的内存.

  1. [root@irora04s~]#free-m
  2. totalusedfreesharedbufferscached
  3. Mem:12902310002428999088512595
  4. -/+buffers/cache:8654342480
  5. Swap:24575024575
  6. [root@irora04s~]#sh/tmp/mem.sh
  7. 4339696KB,66056KB,745.805MB
  8. rss+pagetable+slabinfo=5046.805MB
  9. totalusedfreesharedbufferscached
  10. Mem:12902310009628926088512597
  11. -/+buffers/cache:8661442409
  12. Swap:24575024575

我个人的理解是事先分配的这部分sga内存,大部分是空page页,在未使用时虽然空间被占用了,但该内存地址内并不存在数据,所以一旦该机触发kdump 时,crash 的内存空间占用的磁盘空间 接近于rss+pagetable+slabinfo,小于rss+pagetable+slabinfo+buffers+cached.

最后这里同样推荐有时间看下nmon的源码,因为从nmon的内存统计信息来看,更便于理解内存的几个去向.

相关广告
  • 深入分析linux内存使用的情况详解 深入分析linux内存使用的情况详解 深入分析linux内存使用的情况详解
相关阅读

深入分析linux内存使用的情况详解

2019/10/10 17:46:09 | 谷歌SEO算法 | 百度K站