用free命令看到的cache跟/proc/meminfo看到的为什么不同?

简介: 用free命令看到的cache跟/proc/meminfo看到的为什么不同?

参考

https://gitlab.com/procps-ng/procps

问题

在使用free命令时发现,free命令输出的buff/cache跟从/proc/meminfo里看到的并不相同,这是为什么呢?

  • free命令的输出
root@ubuntu-vm:~# free
              total        used        free      shared  buff/cache   available
Mem:        2915040      203052     2474248        1864      237740     2665100
Swap:       4194300           0     4194300

或者将buff和cache分开显示:

root@ubuntu-vm:~# free -w
              total        used        free      shared     buffers       cache   available
Mem:        2915040      202844     2474456        1864       16356      221384     2665308
Swap:       4194300           0     4194300
  • meminfo的内容
root@ubuntu-vm:~# cat /proc/meminfo
MemTotal:        2915040 kB
MemFree:         2474076 kB
MemAvailable:    2664928 kB
Buffers:           16356 kB
Cached:           172904 kB
SwapCached:            0 kB
Active:            97604 kB
Inactive:         124956 kB
Active(anon):        360 kB
Inactive(anon):    34804 kB
Active(file):      97244 kB
Inactive(file):    90152 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       4194300 kB
SwapFree:        4194300 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:         33332 kB
Mapped:            53588 kB
Shmem:              1864 kB
KReclaimable:      48480 kB
Slab:             179512 kB
SReclaimable:      48480 kB
SUnreclaim:       131032 kB
KernelStack:        3040 kB
PageTables:         1740 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     5651820 kB
Committed_AS:     124320 kB
VmallocTotal:   34359738367 kB
VmallocUsed:        4268 kB
VmallocChunk:          0 kB
Percpu:             1824 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      128884 kB
DirectMap2M:     4065280 kB

上面meminfo的输出里:

Buffers:           16356 kB
Cached:           172904 kB

而free的输出的是:

buffers       cache
16356         221384

其中Buffersbuffers可以对的上,但是Cachedcache就相差很大了。

原因

通过分析free命令的实现,发现了问题所在。free命令输出的cache其实是meminfo中的Cached + SReclaimable。上面SReclaimable的输出是48480,加上172904得到221384, 正好对的上。

man手册里对这个也有解释:

DESCRIPTION
       free  displays  the total amount of free and used physical and swap memory in the system, as well as the buffers and caches used by the kernel. The
       information is gathered by parsing /proc/meminfo. The displayed columns are:
       total  Total installed memory (MemTotal and SwapTotal in /proc/meminfo)
       used   Used memory (calculated as total - free - buffers - cache)
       free   Unused memory (MemFree and SwapFree in /proc/meminfo)
shared Memory used (mostly) by tmpfs (Shmem in /proc/meminfo)
       buffers
              Memory used by kernel buffers (Buffers in /proc/meminfo)
       cache  Memory used by the page cache and slabs (Cached and SReclaimable in /proc/meminfo)
       buff/cache
              Sum of buffers and cache
       available
              Estimation of how much memory is available for starting new applications, without swapping. Unlike the data provided by the  cache  or  free
              fields,  this field takes into account page cache and also that not all reclaimable memory slabs will be reclaimed due to items being in use
              (MemAvailable in /proc/meminfo, available on kernels 3.14, emulated on kernels 2.6.27+, otherwise the same as free)

源码

main
  -> procps_meminfo_new(&mem_info)
    -> meminfo_read_failed(p)
  -> printf(" %11s", scale_size(MEMINFO_GET(mem_info, MEMINFO_MEM_CACHED_ALL, ul_int), flags, args)
  • meminfo_read_failed的源码
/*
 * meminfo_read_failed():
 *
 * Read the data out of /proc/meminfo putting the information
 * into the supplied info structure
 */
static int meminfo_read_failed (
struct meminfo_info *info)
{
/* a 'memory history reference' macro for readability,
    so we can focus the field names ... */
#define mHr(f) info->hist.new. f
char buf[MEMINFO_BUFF];  // 8KB
char *head, *tail;
int size;
unsigned long *valptr;
signed long mem_used;
// remember history from last time around
memcpy(&info->hist.old, &info->hist.new, sizeof(struct meminfo_data));
// clear out the soon to be 'current' values
memset(&info->hist.new, 0, sizeof(struct meminfo_data));
if (-1 == info->meminfo_fd
    && (-1 == (info->meminfo_fd = open(MEMINFO_FILE, O_RDONLY))))
return 1;
if (lseek(info->meminfo_fd, 0L, SEEK_SET) == -1)
return 1;
  // 读取/proc/meminfo的内容到buf中
for (;;) {
if ((size = read(info->meminfo_fd, buf, sizeof(buf)-1)) < 0) {
if (errno == EINTR || errno == EAGAIN)
continue;
return 1;
        }
break;
    }
if (size == 0) {
        errno = EIO;
return 1;
    }
    buf[size] = '\0';
    head = buf;
  // 解析读到的数据
for (;;) {
static __thread ENTRY e;  // keep coverity off our backs (e.data)
        ENTRY *ep;
if (!(tail = strchr(head, ':')))
break;
        *tail = '\0';
        valptr = NULL;
        e.key = head;
if (hsearch_r(e, FIND, &ep, &info->hashtab))
            valptr = ep->data;
        head = tail + 1;
if (valptr)
            *valptr = strtoul(head, NULL, 10);
if (!(tail = strchr(head, '\n')))
break;
        head = tail + 1;
    }
if (0 == mHr(MemAvailable))
        mHr(MemAvailable) = mHr(MemFree);
    mHr(derived_mem_cached) = mHr(Cached) + mHr(SReclaimable);   // 这里derived_mem_cached就是后面输出的cache的数据来源
/* if 'available' is greater than 'total' or our calculation of mem_used
       overflows, that's symptomatic of running within a lxc container where
       such values will be dramatically distorted over those of the host. */
if (mHr(MemAvailable) > mHr(MemTotal))
        mHr(MemAvailable) = mHr(MemFree);
    mem_used = mHr(MemTotal) - mHr(MemAvailable);
if (mem_used < 0)
        mem_used = mHr(MemTotal) - mHr(MemFree);
    mHr(derived_mem_used) = (unsigned long)mem_used;
if (mHr(HighFree) < mHr(HighTotal))
         mHr(derived_mem_hi_used) = mHr(HighTotal) - mHr(HighFree);
if (0 == mHr(LowTotal)) {
        mHr(LowTotal) = mHr(MemTotal);
        mHr(LowFree)  = mHr(MemFree);
    }
if (mHr(LowFree) < mHr(LowTotal))
        mHr(derived_mem_lo_used) = mHr(LowTotal) - mHr(LowFree);
if (mHr(SwapFree) < mHr(SwapTotal))
        mHr(derived_swap_used) = mHr(SwapTotal) - mHr(SwapFree);
return 0;
#undef mHr
} // end: meminfo_read_failed
  • MEMINFO_GET
#define MEMINFO_GET( info, actual_enum, type ) ( { \
    struct meminfo_result *r = procps_meminfo_get( info, actual_enum ); \
    r ? r->result . type : 0; } )
  • procps_meminfo_get
PROCPS_EXPORT struct meminfo_result *procps_meminfo_get (
struct meminfo_info *info,
enum meminfo_item item)
{
time_t cur_secs;
    errno = EINVAL;
if (info == NULL)
return NULL;
if (item < 0 || item >= MEMINFO_logical_end)
return NULL;
    errno = 0;
/* we will NOT read the meminfo file with every call - rather, we'll offer
       a granularity of 1 second between reads ... */
    cur_secs = time(NULL);
if (1 <= cur_secs - info->sav_secs) {
if (meminfo_read_failed(info))
return NULL;
        info->sav_secs = cur_secs;
    }
    info->get_this.item = item;
//  with 'get', we must NOT honor the usual 'noop' guarantee
    info->get_this.result.ul_int = 0;
    Item_table[item].setsfunc(&info->get_this, &info->hist);
return &info->get_this;
} //
  • Item_table
static struct {
    SET_t setsfunc;              // the actual result setting routine
char *type2str;              // the result type as a string value
} Item_table[] = {
/*  setsfunc                   type2str
    -------------------------  ---------- */
 ...
  { RS(MEM_BUFFERS),           TS(ul_int) },
  { RS(MEM_CACHED),            TS(ul_int) },
  { RS(MEM_CACHED_ALL),        TS(ul_int) },
 ...

其中{ RS(MEM_CACHED_ALL), TS(ul_int) }展开后就是

{(SET_t)set_meminfo_MEM_CACHED_ALL, "ul_int"}
  • set_meminfo_MEM_CACHED_ALL
#define setNAME(e) set_meminfo_ ## e
#define setDECL(e) static void setNAME(e) \
    (struct meminfo_result *R, struct mem_hist *H)
// regular assignment
#define MEM_set(e,t,x) setDECL(e) { R->result. t = H->new. x; }
// delta assignment
#define HST_set(e,t,x) setDECL(e) { R->result. t = ( H->new. x - H->old. x ); }
setDECL(noop)  { (void)R; (void)H; }
setDECL(extra) { (void)H; R->result.ul_int = 0; }
...
MEM_set(MEM_BUFFERS,            ul_int,  Buffers)
MEM_set(MEM_CACHED,             ul_int,  Cached)
MEM_set(MEM_CACHED_ALL,         ul_int,  derived_mem_cached)

其中:MEM_set(MEM_CACHED_ALL, ul_int, derived_mem_cached)展开后:

static void set_meminfo_MEM_CACHED_ALL \
    (struct meminfo_result *R, struct mem_hist *H) {R->result.ul_int = H->new.derived_mem_cached;}

其他

与free类似,vmstat和top命令的输出也存在这样的现象:

  • vmstat
root@ubuntu-vm:~# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0      0 2475548  16420 221352    0    0     0     0    2    2  0  0 100  0  0
0  0      0 2475424  16420 221352    0    0     0     0   18   15  0  0 100  0  0
 ...
  • top
root@ubuntu-vm:~# top -b -n 1
top - 22:07:29 up 1 day, 18:08,  1 user,  load average: 0.00, 0.00, 0.00
Tasks:  92 total,   1 running,  91 sleeping,   0 stopped,   0 zombie
%Cpu(s):  0.9 us, 12.0 sy,  0.0 ni, 87.2 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :   2846.7 total,   2415.9 free,    198.3 used,    232.5 buff/cache
MiB Swap:   4096.0 total,   4096.0 free,      0.0 used.   2602.6 avail Mem
...
YAML 复制 全屏
  • free
root@ubuntu-vm:~# free -h
              total        used        free      shared  buff/cache   available
Mem:          2.8Gi       198Mi       2.4Gi       1.0Mi       232Mi       2.5Gi
Swap:         4.0Gi          0B       4.0Gi
相关文章
|
7月前
|
存储 缓存 Linux
free命令详解
`free`命令在Linux中显示内存使用详情,包括总内存(`total`)、已用(`used`,含缓存`buffers/cache`)、空闲(`free`)、共享(`shared`)和可用(`available`)内存。交换空间显示其总量、使用量和剩余量。`-h`选项以易读格式显示,`-m`以MB显示,`-t`显示总和,`-s`定时刷新。例如,`free -ht 5`每5秒更新内存和交换空间的总览。
159 3
|
6月前
|
Linux
linux下清理buffer/cache
linux下清理buffer/cache
|
4月前
|
Linux
Linux——如何清除buff/cache
Linux——如何清除buff/cache
39 0
|
SQL 缓存 Linux
Linux清除缓存buff/cache
Linux清除缓存buff/cache
523 0
|
缓存 算法 Linux
linux通过free查看内存解析和swap的设置
linux通过free查看内存解析和swap的设置
linux通过free查看内存解析和swap的设置
|
存储 缓存 Ubuntu
free命令使用详解
free命令使用详解
186 0
free命令使用详解
|
缓存 Linux
Linux系统中的Page cache和Buffer cache
简单说来,page cache用来缓存文件数据,buffer cache用来缓存磁盘数据。在有文件系统的情况下,对文件操作,那么数据会缓存到page cache,如果直接采用dd等工具对磁盘进行读写,那么数据会缓存到buffer cache。 Buffer(Buffer Cache)以块形式缓冲了块设备的操作,定时或手动的同步到硬盘,它是为了缓冲写操作然后一次性将很多改动写入硬盘,避免频繁写硬盘,提高写入效率。 Cache(Page Cache)以页面形式缓存了文件系统的文件,给需要使用的程序读取,它是为了给读操作提供缓冲,避免频繁读硬盘,提高读取效率。
536 0
Linux系统中的Page cache和Buffer cache
|
Linux
linux free命令下 cached占用很大
# 背景 使用free -h命令,展示如下:   # 解决方法 先执行sync命令,同步数据 然后执行 echo 1 > /proc/sys/vm/drop_caches echo 2 > /proc/sys/vm/drop_caches echo 3 > /proc/sys/v...
1823 0
|
缓存 Linux 存储
【linux】free命令中cached和buffers的区别
一、命令 1 2 3 4 5 [root@localhost ~]# free -m              total       used       free     shared    buffers     cached Mem:          7869  .
2380 0