专栏首页运维之美都说 Linux 是吃内存大户,可你知道具体是哪些进程吃掉了吗?

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

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

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

比较老的资料都会介绍 LinuxCache 占用很多并没有关系,因为 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

虽然上面的命令显示了 CacheSlab 的情况,但是还是没有显示什么程序占用的 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.
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 
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 
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 DataKernelPage Cache Table 做对比,如果 Page Cache Table 有这个 Inode 信息,就找到该 Inode 对应的 Data Block 的大小。

因为 KernelPage 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 一样 。

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

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

#!/bin/bash

#you have to install pcstat
if [ ! -f /data0/brokerproxy/pcstat ]
then
    echo "You haven't installed pcstat yet"
    echo "run \"go get github.com/tobert/pcstat\" to install"
    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.pcstat ]
then
    echo "the cache.pcstat is exist, removing now"
    rm -f /tmp/cache.pcstat
fi

for i in `cat /tmp/cache.files`
do
    if [ -f $i ]
    then
        echo $i >>/tmp/cache.pcstat
    fi
done

/data0/brokerproxy/pcstat  `cat /tmp/cache.pcstat`
rm -f /tmp/cache.{pids,files,pcstat}

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

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

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

方案二:使用 Vmtouch 来实现

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

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

安装 Vmtouch

$ git clone https://github.com/hoytech/vmtouch
$ cd vmtouch
$ make
$ sudo make install

使用 Vmtouch

  1. vmtouch 命令语法
$ vmtouch
vmtouch: no files or directories specified

vmtouch v1.0.2 - the Virtual Memory Toucher by Doug Hoyte
Portable file system cache diagnostics and control

Usage: vmtouch [OPTIONS] ... FILES OR DIRECTORIES ...

Options:
  -t touch pages into memory
  -e evict pages from memory
  -l lock pages in physical memory with mlock(2)
  -L lock pages in physical memory with mlockall(2)
  -d daemon mode
  -m max file size to touch
  -p use the specified portion instead of the entire file
  -f follow symbolic links
  -h also count hardlinked copies
  -w wait until all pages are locked (only useful together with -d)
  -v verbose
  -q quiet
  1. 一些使用的例子

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

  • 查看 /tmp 目录在内存中的缓存
$ vmtouch /tmp/
vmtouch: WARNING: skipping non-regular file: /tmp/ssh-GgJnCEkWMQC2/agent.1068

           Files: 17
     Directories: 7
  Resident Pages: 4780/4780  18M/18M  100%
         Elapsed: 0.001006 seconds

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

$ vmtouch -v /tmp/
  • 查看一个文件被缓存了多少
$ vmtouch -v ~/Downloads/phoronix-test-suite_6.0.1_all.deb 
/home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb
[                                            ] 0/132

           Files: 1
     Directories: 0
  Resident Pages: 0/132  0/528K  0%
         Elapsed: 0.000117 seconds
  • 把指定的文件缓存起来
$ vmtouch -vt ~/Downloads/phoronix-test-suite_6.0.1_all.deb 
/home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb
[OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO] 132/132

           Files: 1
     Directories: 0
   Touched Pages: 132 (528K)
         Elapsed: 0.007935 seconds
  • 把缓存中指定的数据驱逐出去
$ vmtouch -ve ~/Downloads/phoronix-test-suite_6.0.1_all.deb 
Evicting /home/neo/Downloads/phoronix-test-suite_6.0.1_all.deb

           Files: 1
     Directories: 0
   Evicted Pages: 132 (528K)
         Elapsed: 0.000109 seconds

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

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

参考文档

  1. https://www.google.com
  2. https://colobu.com/2017/03/07/what-is-in-linux-cached/
  3. https://www.cnblogs.com/langdashu/p/5953222.html

本文分享自微信公众号 - 运维之美(Hi-Linux),作者:Mike

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 你是否经常忘记 Linux 计划任务 Crontab 复杂的语法格式呢,用上这款神器后再也不用担心了!

    Linux / Unix 系统里有一个很方便的程序「例行性计划任务」(Crontab),接触过的朋友一定不陌生。Crontab 主要是让系统去执行一些固定时间要...

    iMike
  • 手把手教你解决 Chrome、IE 等浏览器无法正常访问 Kubernetes Dashboard 的问题

    一般情况下,正常安装部署完 Kubernetes Dashboard 后,通过大多数主流浏览器(Chrome、IE、Safari)是不能正常访问的,唯有 Fir...

    iMike
  • 你不可错过的 GitHub 万星技术面试宝典

    最近,GitHub 上有一个很火的项目,截止目前,该项目已获得 17000+ Star。该项目主要介绍了阿里巴巴、华为、百度、腾讯、美团、字节跳动、滴滴、京东等...

    iMike
  • LeetCode 186. 翻转字符串里的单词 II

    Michael阿明
  • 从零开始学C++之STL(一):STL六大组件简介

    一、STL简介 (一)、泛型程序设计 泛型编程(generic programming) 将程序写得尽可能通用 将算法从数据结构中抽象出来,成为通用的 C...

    s1mba
  • Mixed Content: xxx This request has been blocked; the content must be served over HTTPS.

    joshua317
  • 谷歌如重返中国TensorFlow将成利器,谷歌董事长评中美AI差距

    【新智元导读】 谷歌再次尝试返回中国,这次依靠的不是搜索,而是人工智能系统开发框架TensorFlow。但是有消息人士称,百度的PaddlePaddle今年在开...

    新智元
  • MySql缓存中的关键项

    MySql的设计中大量使用了缓存,下面这些缓存配置项是应该熟知的 key_buffer_size key_buffer_size是设置MyISAM表索引的缓冲区...

    dys
  • 小程序已失败?那你理解小程序了吗?

    知晓君
  • 流程控制-9(上)

    本文目录 前言 一、顺序结构 二、选择结构1-if语句 三、选择结构2-switch语句 前言 1.默认的运行流程 默认情况下,程序的运行流程...

    Python知识大全

扫码关注云+社区

领取腾讯云代金券