都说Linux是吃内存大户,可你知道具体是哪些进程吃掉了吗?

系统 Linux
一个经常被问到的 Linux 问题:为啥 Linux 系统没运行多少程序,显示的可用内存这么少?其实 Linux 与 Windows 的内存管理不同,会尽量缓存内存以提高读写性能,通常叫做 Cache Memory。

 [[280238]]

一个经常被问到的 Linux 问题:为啥 Linux 系统没运行多少程序,显示的可用内存这么少?

其实 Linux 与 Windows 的内存管理不同,会尽量缓存内存以提高读写性能,通常叫做 Cache Memory。

比较老的资料都会介绍 Linux 的 Cache 占用很多并没有关系,因为 Linux 会尽可能利用内存进行缓存。但是缓存的回收也是需要资源的,比较好的一篇文章是 Poor Zorro 写的 Linux 内存中的 Cache 真的能被回收么?。

虽然大部分情况下我们看到 Cache 占用很高时是没有问题的,但是我们还是想弄清楚到底是哪个程序把 Cache 弄的那么高,这居然不是一件容易的事。

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

  1. # 显示了一台机器缓存中占用对象的情况  
  2. $ slabtop -s c   
  3. Active / Total Objects (% used)    : 856448 / 873737 (98.0%)  
  4.  Active / Total Slabs (% used)      : 19737 / 19737 (100.0%)  
  5.  Active / Total Caches (% used)     : 67 / 89 (75.3%)  
  6.  Active / Total Size (% used)       : 141806.80K / 145931.33K (97.2%)  
  7.  Minimum / Average / Maximum Object : 0.01K / 0.17K / 8.00K  
  8.   OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME  
  9. 416949 416949 100%    0.10K  10691   39     42764K buffer_head  
  10.   5616   5545  98%    2.00K    351   16     11232K kmalloc-2048  
  11.   9114   8990  98%    1.02K    294   31  9408K ext4_inode_cache  
  12.  12404  12404 100%    0.57K    443   28  7088K radix_tree_node  
  13.  10800  10731  99%    0.58K    400   27  6400K inode_cache  
  14.  31290  29649  94%    0.19K    745   42  5960K dentry  
  15.   3552   3362  94%    1.00K    111   32  3552K kmalloc-1024  
  16.   1100   1055  95%    2.84K    100   11  3200K task_struct  
  17.   1649   1481  89%    1.88K     97   17  3104K TCP  
  18.  27000  27000 100%    0.11K    750   36  3000K sysfs_dir_cache  
  19.   1380   1269  91%    2.06K     92   15  2944K sighand_cache 

虽然上面的命令显示了 Cache 中 Slab 的情况,但是还是没有显示什么程序占用的 Cache。

方案一:使用 Pcstat 来实现

经过搜索,发现 linux-ftools 这个工具可以显示某个文件占用的 Cache 的情况, fincore 只是它其中的一个工具。 

  1. $ fincore [options] files...  
  2.   --pages=false      Do not print pages  
  3.   --summarize        When comparing multiple files, print a summary report  
  4.   --only-cached      Only print stats for files that are actually in cache.  
  5. https://colobu.com/2017/03/07/what-is-in-linux-cached/root@xxxxxx:/var/lib/mysql/blogindex# fincore --pages=false --summarize --only-cached *   
  6. stats for CLUSTER_LOG_2010_05_21.MYI: file size=93840384 , total pages=22910 , cached pages=1 , cached size=4096, cached perc=0.004365   
  7. stats for CLUSTER_LOG_2010_05_22.MYI: file size=417792 , total pages=102 , cached pages=1 , cached size=4096, cached perc=0.980392   
  8. stats for CLUSTER_LOG_2010_05_23.MYI: file size=826368 , total pages=201 , cached pages=1 , cached size=4096, cached perc=0.497512   
  9. stats for CLUSTER_LOG_2010_05_24.MYI: file size=192512 , total pages=47 , cached pages=1 , cached size=4096, cached perc=2.127660  
  10.  stats for CLUSTER_LOG_2010_06_03.MYI: file size=345088 , total pages=84 , cached pages=43 , cached size=176128, cached perc=51.190476   
  11. stats for CLUSTER_LOG_2010_06_04.MYD: file size=1478552 , total pages=360 , cached pages=97 , cached size=397312, cached perc=26.944444   
  12. stats for CLUSTER_LOG_2010_06_04.MYI: file size=205824 , total pages=50 , cached pages=29 , cached size=118784, cached perc=58.000000   
  13. stats for COMMENT_CONTENT_2010_06_03.MYI: file size=100051968 , total pages=24426 , cached pages=10253 , cached size=41996288, cached perc=41.975764   
  14. stats for COMMENT_CONTENT_2010_06_04.MYD: file size=716369644 , total pages=174894 , cached pages=79821 , cached size=326946816, cached perc=45.639645   
  15. stats for COMMENT_CONTENT_2010_06_04.MYI: file size=56832000 , total pages=13875 , cached pages=5365 , cached size=21975040, cached perc=38.666667   
  16. stats for FEED_CONTENT_2010_06_03.MYI: file size=1001518080 , total pages=244511 , cached pages=98975 , cached size=405401600, cached perc=40.478751   
  17. stats for FEED_CONTENT_2010_06_04.MYD: file size=9206385684 , total pages=2247652 , cached pages=1018661 , cached size=4172435456, cached perc=45.321117   
  18. stats for FEED_CONTENT_2010_06_04.MYI: file size=638005248 , total pages=155763 , cached pages=52912 , cached size=216727552, cached perc=33.969556   
  19. stats for FEED_CONTENT_2010_06_04.frm: file size=9840 , total pages=2 , cached pages=3 , cached size=12288, cached perc=150.000000   
  20. stats for PERMALINK_CONTENT_2010_06_03.MYI: file size=1035290624 , total pages=252756 , cached pages=108563 , cached size=444674048, cached perc=42.951700   
  21. stats for PERMALINK_CONTENT_2010_06_04.MYD: file size=55619712720 , total pages=13579031 , cached pages=6590322 , cached size=26993958912, cached perc=48.533080   
  22. stats for PERMALINK_CONTENT_2010_06_04.MYI: file size=659397632 , total pages=160985 , cached pages=54304 , cached size=222429184, cached perc=33.732335   
  23. stats for PERMALINK_CONTENT_2010_06_04.frm: file size=10156 , total pages=2 , cached pages=3 , cached size=12288, cached perc=150.000000   
  24. ---  
  25. total cached size: 32847278080 

fincore 的工作原理是将指定文件的相应 Inode Data 与 Kernel 的 Page Cache Table 做对比,如果 Page Cache Table 有这个 Inode 信息,就找到该 Inode 对应的 Data Block 的大小。

因为 Kernel 的 Page Cache Table 只存储 Data Block 的引用而不是文件名,即文件的 Inode 信息。所以并没有任何一个工具运行一次就可以找出所有的文件使用缓存的情况。所以使用 linux-fincore 这个工具也只能加文件名来判断该文件是否被缓存,如果缓存,大小是多少。问题是你不能随便猜哪个文件是否被缓存吧。

Shanker 提供了一个脚本来解决此问题,那就是查看哪些进程使用的物理内存最多,就找到该进程打开的文件,然后用 fincore 来查看这些文件的缓存使用率。

这个办法在大部分情况下都可以找到占用 Cache 较多的程序和进程。脚本内容如下: 

  1. #!/bin/bash  
  2. #Author: Shanker  
  3. #Time: 2016/06/08  
  4. #set -e  
  5. #set -u  
  6. #you have to install linux-fincore  
  7. if [ ! -f /usr/local/bin/linux-fincore ]  
  8. then  
  9.     echo "You haven't installed linux-fincore yet"  
  10.     exit  
  11. fi  
  12. #find the top 10 processs' cache file  
  13. ps -e -o pid,rss|sort -nk2 -r|head -10 |awk '{print $1}'>/tmp/cache.pids   
  14. #find all the processs' cache file  
  15. #ps -e -o pid>/tmp/cache.pids  
  16. if [ -f /tmp/cache.files ]  
  17. then  
  18.     echo "the cache.files is exist, removing now "  
  19.     rm -f /tmp/cache.files  
  20. fi  
  21. while read line  
  22. do  
  23.     lsof -p $line 2>/dev/null|awk '{print $9}' >>/tmp/cache.files   
  24. done</tmp/cache.pids  
  25. if [ -f /tmp/cache.fincore ]  
  26. then  
  27.     echo "the cache.fincore is exist, removing now"  
  28.     rm -f /tmp/cache.fincore  
  29. fi  
  30. for i in `cat /tmp/cache.files`  
  31. do  
  32.     if [ -f $i ]  
  33.     then  
  34.         echo $i >>/tmp/cache.fincore  
  35.     fi  
  36. done  
  37. linux-fincore -s  `cat /tmp/cache.fincore`  
  38. rm -f /tmp/cache.{pids,files,fincore} 

比较遗憾的是,linux-ftools 目前已经不再维护了。在新版本的操作系统上没法编译好这个程序,所以这个方法失效了。

再次通过 Google 搜索,后来我找到了 pcstat 这个工具,pcstat 使用 Go 语言开发,功能基本和 linux-ftools 一样 。

项目地址:https://github.com/tobert/pcstat

然后我修改了 Shanker 的脚本,让它使用 pcstat 来进行处理,这样就可以很好的找到 Cache 所占用的情况。修改后的脚本如下: 

  1. #!/bin/bash  
  2. #you have to install pcstat  
  3. if [ ! -f /data0/brokerproxy/pcstat ]  
  4. then  
  5.     echo "You haven't installed pcstat yet"  
  6.     echo "run \"go get github.com/tobert/pcstat\" to install"  
  7.     exit  
  8. fi  
  9. #find the top 10 processs' cache file  
  10. ps -e -o pid,rss|sort -nk2 -r|head -10 |awk '{print $1}'>/tmp/cache.pids  
  11. #find all the processs' cache file  
  12. #ps -e -o pid>/tmp/cache.pids  
  13. if [ -f /tmp/cache.files ]  
  14. then  
  15.     echo "the cache.files is exist, removing now "  
  16.     rm -f /tmp/cache.files  
  17. fi  
  18. while read line  
  19. do  
  20.     lsof -p $line 2>/dev/null|awk '{print $9}' >>/tmp/cache.files   
  21. done</tmp/cache.pids  
  22. if [ -f /tmp/cache.pcstat ]  
  23. then  
  24.     echo "the cache.pcstat is exist, removing now"  
  25.     rm -f /tmp/cache.pcstat 
  26. fi  
  27. for i in `cat /tmp/cache.files`  
  28. do  
  29.     if [ -f $i ]  
  30.     then  
  31.         echo $i >>/tmp/cache.pcstat  
  32.     fi  
  33. done  
  34. /data0/brokerproxy/pcstat  `cat /tmp/cache.pcstat`  
  35. rm -f /tmp/cache.{pids,files,pcstat} 

脚本运行成功后的显示结果如下: 

  1. +------------------------------------------+----------------+------------+-----------+---------+  
  2. | Name                                     | Size (bytes)   | Pages      | Cached    | Percent |  
  3. |------------------------------------------+----------------+------------+-----------+---------|  
  4. | /data0/abcasyouknow/0307/abc             | 10060771       | 2457       | 2457      | 100.000 |  
  5. | /data0/abcasyouknow/0307/logs/abc.log    | 1860           | 1          | 1         | 100.000 |  
  6. | /data0/abcasyouknow/0307/logs/uuid.log   | 326326364      | 79670      | 79670     | 100.000 |  
  7. | /usr/bin/bash                            | 960384         | 235        | 194       | 082.553 |  
  8. | /usr/lib/locale/locale-archive           | 106065056      | 25895      | 211       | 000.815 |  
  9. | /usr/lib64/libnss_files-2.17.so          | 58288          | 15         | 15        | 100.000 |  
  10. | /usr/lib64/libc-2.17.so                  | 2107760        | 515        | 336       | 065.243 |  
  11. | /usr/lib64/libdl-2.17.so                 | 19512          | 5          | 5         | 100.000 |  
  12. | /usr/lib64/libtinfo.so.5.9               | 174520         | 43         | 42        | 097.674 |  
  13. | /usr/lib64/ld-2.17.so                    | 164336         | 41         | 41        | 100.000 |  
  14. | /usr/lib64/gconv/gconv-modules.cache     | 26254          | 7          | 7         | 100.000 |  
  15. +------------------------------------------+----------------+------------+-----------+---------+ 

从结果我们可以看到 uuid.log 占用 Cache 比较多。这个文件是打开的,程序一直在往里面写日志,Linux 应该是把它缓存了。

方案二:使用 Vmtouch 来实现

除了上面提到的 pcstat 工具外,你还可以使用 vmtouch 来实现同样的目的。vmtouch 是一个可以查询到缓存的文件和目录,并且能把文件推入缓存或者驱逐出缓存的工具。 

项目地址:https://github.com/hoytech/vmtouch

安装 Vmtouch 

  1. $ git clone https://github.com/hoytech/vmtouch  
  2. $ cd vmtouch  
  3. $ make  
  4. $ sudo make install 

使用 Vmtouch

  1. vmtouch 命令语法 
  1. $ vmtouch  
  2. vmtouch: no files or directories specified  
  3. vmtouch v1.0.2 - the Virtual Memory Toucher by Doug Hoyte  
  4. Portable file system cache diagnostics and control  
  5. Usage: vmtouch [OPTIONS] ... FILES OR DIRECTORIES ...  
  6. Options:  
  7.   -t touch pages into memory  
  8.   -e evict pages from memory  
  9.   -l lock pages in physical memory with mlock(2)  
  10.   -L lock pages in physical memory with mlockall(2)  
  11.   -d daemon mode  
  12.   -m max file size to touch  
  13.   -p use the specified portion instead of the entire file  
  14.   -f follow symbolic links  
  15.   -h also count hardlinked copies  
  16.   -w wait until all pages are locked (only useful together with -d)  
  17.   -v verbose  
  18.   -q quiet 

    2.   一些使用的例子

由于 vmtouch 直接支持目录级查询,所以使用起来简单得多了。

  •  查看 /tmp 目录在内存中的缓存 
  1. $ vmtouch /tmp/  
  2. vmtouch: WARNING: skipping non-regular file: /tmp/ssh-GgJnCEkWMQC2/agent.1068  
  3.            Files: 17  
  4.      Directories: 7  
  5.   Resident Pages: 4780/4780  18M/18M  100%  
  6.          Elapsed: 0.001006 seconds 

如果需要查看更详细信息,可以使用 -v 参数。 

  1. $ vmtouch -v /tmp/ 
  •  查看一个文件被缓存了多少 
  1. $ vmtouch -v ~/Downloads/phoronix-test-suite_6.0.1_all.deb   
  2. /home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb  
  3. [                                            ] 0/132  
  4.            Files: 1  
  5.      Directories: 0  
  6.   Resident Pages: 0/132  0/528K  0%  
  7.          Elapsed: 0.000117 seconds 
  •  把指定的文件缓存起来 
  1. $ vmtouch -vt ~/Downloads/phoronix-test-suite_6.0.1_all.deb   
  2. /home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb  
  3. [OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO] 132/132  
  4.            Files: 1  
  5.      Directories: 0  
  6.    Touched Pages: 132 (528K)  
  7.          Elapsed: 0.007935 seconds 
  •  把缓存中指定的数据驱逐出去 
  1. $ vmtouch -ve ~/Downloads/phoronix-test-suite_6.0.1_all.deb   
  2. Evicting /home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb  
  3.            Files: 1  
  4.      Directories: 0  
  5.    Evicted Pages: 132 (528K)  
  6.          Elapsed: 0.000109 seconds 

更多关于 vmtouch 使用的具体信息,你可以参考官网:https://hoytech.com/vmtouch/

如果你还有更多 Linux 下查看 Cache 或 Buffer 占用的方法,请直接留言告诉我们哟! 

 

责任编辑:庞桂玉 来源: 运维之美
相关推荐

2017-10-12 10:06:23

Linux内存free命令

2024-10-31 08:36:32

2022-10-31 10:03:03

2022-11-28 14:27:17

插入意向锁age

2016-10-11 08:53:38

Chrome浏览器Google

2022-12-30 08:35:00

2015-09-11 15:56:52

内核构建Linux

2022-09-19 13:21:15

Linux进程

2012-09-28 09:48:57

数据中心能耗机房

2018-03-04 16:41:30

SaaS云计算企业

2020-06-15 14:36:15

2024-01-26 06:26:42

Linuxfzf工具

2022-08-01 11:32:57

Linux内核版本

2021-11-03 16:25:26

Linux磁盘空间命令

2023-10-28 09:00:03

进程系统服务

2023-08-30 07:27:39

2022-09-28 18:16:34

JavaJDK

2023-12-20 08:23:53

NIO组件非阻塞

2015-12-01 13:33:51

UnikernelLinux运维

2021-11-12 05:59:23

容灾备份5G
点赞
收藏

51CTO技术栈公众号