• 用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
    ...
    
    • 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
    
  • 相关阅读:
    2019 西安邀请赛 D
    time 库
    字符串处理+格式化输出
    数据类型
    turtle1
    格式问题
    字符串1
    基础操作
    链表去重
    PAT 1093
  • 原文地址:https://www.cnblogs.com/pengdonglin137/p/16567740.html
Copyright © 2020-2023  润新知