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

副标题#e#

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

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

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

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

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

# 显示了一台机器缓存中占用对象的情况  

$ slabtop -s c   

Active / Total Objects (% used)    : 856448 / 873737 (98.0%)  

 Active / Total Slabs (% used)      : 19737 / 19737 (100.0%)  

 Active / Total Caches (% used)     : 67 / 89 (75.3%)  

 Active / Total Size (% used)       : 141806.80K / 145931.33K (97.2%)  

 Minimum / Average / Maximum Object : 0.01K / 0.17K / 8.00K  

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME  

416949 416949 100%    0.10K  10691   39     42764K buffer_head  

  5616   5545  98%    2.00K    351   16     11232K kmalloc-2048  

  9114   8990  98%    1.02K    294   31  9408K ext4_inode_cache  

 12404  12404 100%    0.57K    443   28  7088K radix_tree_node  

 10800  10731  99%    0.58K    400   27  6400K inode_cache  

 31290  29649  94%    0.19K    745   42  5960K dentry  

  3552   3362  94%    1.00K    111   32  3552K kmalloc-1024  

  1100   1055  95%    2.84K    100   11  3200K task_struct  

  1649   1481  89%    1.88K     97   17  3104K TCP  

 27000  27000 100%    0.11K    750   36  3000K sysfs_dir_cache  

  1380   1269  91%    2.06K     92   15  2944K sighand_cache 

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

方案一:使用 Pcstat 来实现

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

$ fincore [options] files...  

  --pages=false      Do not print pages  

  --summarize        When comparing multiple files, print a summary report  

  --only-cached      Only print stats for files that are actually in cache.  

#p#副标题#e#

https://colobu.com/2017/03/07/what-is-in-linux-cached/root@xxxxxx:/var/lib/mysql/blogindex# fincore --pages=false --summarize --only-cached *   

stats for CLUSTER_LOG_2010_05_21.MYI: file size=93840384 , total pages=22910 , cached pages=1 , cached size=4096, cached perc=0.004365   

#p#副标题#e##p#分页标题#e#

stats for CLUSTER_LOG_2010_05_22.MYI: file size=417792 , total pages=102 , cached pages=1 , cached size=4096, cached perc=0.980392   

stats for CLUSTER_LOG_2010_05_23.MYI: file size=826368 , total pages=201 , cached pages=1 , cached size=4096, cached perc=0.497512   

stats for CLUSTER_LOG_2010_05_24.MYI: file size=192512 , total pages=47 , cached pages=1 , cached size=4096, cached perc=2.127660  

 stats for CLUSTER_LOG_2010_06_03.MYI: file size=345088 , total pages=84 , cached pages=43 , cached size=176128, cached perc=51.190476   

stats for CLUSTER_LOG_2010_06_04.MYD: file size=1478552 , total pages=360 , cached pages=97 , cached size=397312, cached perc=26.944444   

stats for CLUSTER_LOG_2010_06_04.MYI: file size=205824 , total pages=50 , cached pages=29 , cached size=118784, cached perc=58.000000   

stats for COMMENT_CONTENT_2010_06_03.MYI: file size=100051968 , total pages=24426 , cached pages=10253 , cached size=41996288, cached perc=41.975764   

stats for COMMENT_CONTENT_2010_06_04.MYD: file size=716369644 , total pages=174894 , cached pages=79821 , cached size=326946816, cached perc=45.639645   

#p#副标题#e#

stats for COMMENT_CONTENT_2010_06_04.MYI: file size=56832000 , total pages=13875 , cached pages=5365 , cached size=21975040, cached perc=38.666667   

stats for FEED_CONTENT_2010_06_03.MYI: file size=1001518080 , total pages=244511 , cached pages=98975 , cached size=405401600, cached perc=40.478751   

stats for FEED_CONTENT_2010_06_04.MYD: file size=9206385684 , total pages=2247652 , cached pages=1018661 , cached size=4172435456, cached perc=45.321117   

stats for FEED_CONTENT_2010_06_04.MYI: file size=638005248 , total pages=155763 , cached pages=52912 , cached size=216727552, cached perc=33.969556   

stats for FEED_CONTENT_2010_06_04.frm: file size=9840 , total pages=2 , cached pages=3 , cached size=12288, cached perc=150.000000   

stats for PERMALINK_CONTENT_2010_06_03.MYI: file size=1035290624 , total pages=252756 , cached pages=108563 , cached size=444674048, cached perc=42.951700   

stats for PERMALINK_CONTENT_2010_06_04.MYD: file size=55619712720 , total pages=13579031 , cached pages=6590322 , cached size=26993958912, cached perc=48.533080   

stats for PERMALINK_CONTENT_2010_06_04.MYI: file size=659397632 , total pages=160985 , cached pages=54304 , cached size=222429184, cached perc=33.732335   

stats for PERMALINK_CONTENT_2010_06_04.frm: file size=10156 , total pages=2 , cached pages=3 , cached size=12288, cached perc=150.000000   

---  

total cached size: 32847278080 

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

#p#副标题#e#

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

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

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

#!/bin/bash  

#Author: Shanker  

#Time: 2016/06/08  

#set -e  

#set -u  

#you have to install linux-fincore  

if [ ! -f /usr/local/bin/linux-fincore ]  

then  

    echo "You haven't installed linux-fincore yet"  

    exit  

fi  

#find the top 10 processs' cache file  

ps -e -o pid,rss|sort -nk2 -r|head -10 |awk '{print $1}'>/tmp/cache.pids   

#find all the processs' cache file  

#ps -e -o pid>/tmp/cache.pids  

if [ -f /tmp/cache.files ]  

then  

    echo "the cache.files is exist, removing now "  

    rm -f /tmp/cache.files  

fi  

while read line  

do  

    lsof -p $line 2>/dev/null|awk '{print $9}' >>/tmp/cache.files   

done</tmp/cache.pids  

if [ -f /tmp/cache.fincore ]  

then  

    echo "the cache.fincore is exist, removing now"  

    rm -f /tmp/cache.fincore  

fi  

for i in `cat /tmp/cache.files`  

do  

    if [ -f $i ]  

    then  

        echo $i >>/tmp/cache.fincore  

    fi  

done  

linux-fincore -s  `cat /tmp/cache.fincore`  

rm -f /tmp/cache.{pids,files,fincore} 

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

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

dawei

【声明】:站长网内容转载自互联网,其相关言论仅代表作者个人观点绝非权威,不代表本站立场。如您发现内容存在版权问题,请提交相关链接至邮箱:bqsm@foxmail.com,我们将及时予以处理。