/proc/meminfo 文件

参考:http://linuxperf.com/?cat=7

/proc/meminfo是了解Linux系统内存使用状况的主要接口,我们的命令行工具free、vmstat等都是通过此接口获得;但是他的信息远比free等命令丰富的多;接下来对此文件进行探究。
内核负责输出/proc/meminfo的源代码是:fs/proc/meminfo.c : meminfo_proc_show();基本的内容如下所示:

MemTotal:除了系统引导fireware和bios保留的一些内存,kernel本身占用的内存外,其余可供内核支配的内存,就是MemTotal;
MemFree:表示系统尚未使用的内存。[MemTotal-MemFree]就是已被用掉的内存;
MemAvailable:有些应用程序会根据系统的可用内存大小自动调整内存申请的多少,所以需要一个记录当前可用内存数量的统计值,MemFree并不适用,因为MemFree不能代表全部可用的内存,系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存,即MemAvailable。/proc/meminfo中的MemAvailable是内核使用特定的算法估算出来的,要注意这是一个估计值,并不精确!
Buffers:表示块设备(block device)所占用的缓存页,包括:直接读写块设备、以及文件系统元数据(metadata)比如SuperBlock所使用的缓存页。
Cached:表示普通文件所占用的缓存页,即page cache所占用的内存大小。
SwapCache:每一个交换区设备在内存里都有对应的swap cache,可以把swap cache理解为交换区设备的”page cache”:page cache对应的是一个个文件,swap cache对应的是一个个交换区设备。
          注:并不是每一个匿名页都在swap cache中,只有以下情形之一的匿名页才在:
        匿名页即将被swap-out时会先被放进swap cache,但通常只存在很短暂的时间,因为紧接着在pageout完成之后它就会从swap cache中删除,毕竟swap-out的目的就是为了腾出空闲内存;
       【注:参见mm/vmscan.c: shrink_page_list(),它调用的add_to_swap()会把swap cache页面标记成dirty,然后它调用try_to_unmap()将页面对应的page table mapping都删除,再调用pageout()回写dirty page,最后try_to_free_swap()会把该页从swap cache中删除。】
         曾经被swap-out现在又被swap-in的匿名页会在swap cache中,直到页面中的内容发生变化、或者原来用过的交换区空间被回收为止。
     【注:当匿名页的内容发生变化时会删除对应的swap cache,代码参见mm/swapfile.c: reuse_swap_page()。】
附加知识:Kernel的动态内存分配通过以下几种接口:
                 alloc_pages/__get_free_page: 以页为单位分配
                 vmalloc: 以字节为单位分配虚拟地址连续的内存块
                 slab allocator
                 kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32、kmalloc-64等(在老kernel上的名称是size-32、size-64等)。
                通过slab层分配的内存会被精确统计,可以参见/proc/meminfo中的slab/SReclaimable/SUnreclaim;
                通过vmalloc分配的内存也有统计,参见/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo;
                而通过alloc_pages分配的内存不会自动统计,除非调用alloc_pages的内核模块或驱动程序主动进行统计,否则我们只能看到free memory减少了,但从/proc/meminfo中看不出它们具体用到哪里去了。
SReclaimable: slab中可回收的部分。调用kmem_getpages()时加上SLAB_RECLAIM_ACCOUNT标记,表明是可回收的,计入SReclaimable,否则计入SUnreclaim。
SUnreclaim: slab中不可回收的部分。
Slab: slab中所有的内存,等于以上两者之和。
附加疑问:为什么 sync;echo 3  > /proc/sys/vm/drop_caches后,free看到的Cached的值未减小?
         1.drop_caches接受以下三种值:
                  1)释放pagecache;        echo 1 > /proc/sys/vm/drop_caches
            2)释放可回收的slab对象 (includes dentries and inodes);  echo 2 > /proc/sys/vm/drop_caches
            3)释放以上所有;                echo 3 > /proc/sys/vm/drop_caches
        2.了解不同版本procps,free命令Cache的计算方法:
        1)版本:procps-3.2.8-36;cache值等于/proc/meminfo中的  [Cached];
        2)版本:procps-3.3.9-10.1;cache值等于/proc/meminfo的   [Cached + SReclaimable];
        3)版本:procps-ng-3.3.10-3;cache值等于/proc/meminfo的 [Cached + Slab]。
        3.drop_cache内存回收的原则
        1)只回收clean pages,不回收dirty pages;所以如果想回收更多的cache,应该在drop_caches之前先执行sync命令,把dirty pages变成clean pages。
        2)   Page cache用于缓存文件里的数据,不仅包括普通的磁盘文件,还包括了tmpfs文件,tmpfs文件系统是将一部分内存空间模拟成文件系统,由于背后并没有对应着磁盘,无法进行paging(换页),只能进行swapping(交换),在执行drop_cache操作的时候tmpfs对应的page cache并不会回收。
        3)Linux kernel利用tmpfs实现共享内存,所以共享内存也和tmpfs一样,属于page cache,但又不能被drop_caches回收。
    共享内存包括
             SysV shared memory:是通过shmget申请的共享内存,用ipcs -mcat /proc/sysvipc/shm查看;
              POSIX shared memory:是通过shm_open申请的共享内存,用ls /dev/shm查看;
             tmpfs文件系统和devtmpfs文件系统:所有tmpfs文件系统占用的空间都计入共享内存,devtmpfs是/dev文件系统的类型,/dev/下所有的文件占用的空间也属于共享内存。可以用ls和du命令查看。如果文件没有关闭的情况下被删除,空间仍然不会释放,可以用 lsof -a +L1 /<mount_point>” 命令查看。
             shared anonymous mmap:通过mmap(…MAP_ANONYMOUS|MAP_SHARED…)申请的内存,可以用”pmap -x”或者”cat /proc/<PID>/maps”查看;
注:mmap调用参数如果不是MAP_ANONYMOUS|MAP_SHARED,则不属于tmpfs,比如MAP_ANONYMOUS|MAP_PRIVATE根本不属于page cache而是属于AnonPages,MAP_SHARED属于普通文件,对应的page cache可以回写硬盘并回收。
VmallocUsed:通过vmalloc分配的内存都统计在/proc/meminfo的 VmallocUsed 值中,不过他不光是包括了分配的物理内存,还统计了VM_IOREMAP、VM_MAP等操作的值,譬如VM_IOREMAP是把IO地址映射到内核空间、并未消耗物理内存,所以我们要把它们排除在外。从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到:
通过vmalloc分配了多少内存,可以统计/proc/vmallocinfo中的vmalloc记录,例如:
        # grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}'
HardwareCorrupted:当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用,/proc/meminfo中的HardwareCorrupted统计了删除掉的内存页的总大小。
Hugepages:在/proc/meminfo中是被独立统计的,与其它统计项不重叠,既不计入进程的RSS/PSS中,又不计入LRU Active/Inactive,也不会计入cache/buffer。如果进程使用了Hugepages,它的RSS/PSS不会增加。
    使用Hugepages有三种方式
    (详见 https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt)
1.mount一个特殊的 hugetlbfs 文件系统,在上面创建文件,然后用mmap() 进行访问,如果要用 read() 访问也是可以的,但是 write() 不行。
2.通过shmget/shmat也可以使用Hugepages,调用shmget申请共享内存时要加上 SHM_HUGETLB 标志。
3.通过 mmap(),调用时指定MAP_HUGETLB 标志也可以使用Huagepages。
       用户程序在申请Hugepages的时候,其实是reserve了一块内存,并未真正使用,此时/proc/meminfo中的 HugePages_Rsvd 会增加,而 HugePages_Free 不会减少。
       等到用户程序真正读写Hugepages的时候,它才被消耗掉了,此时HugePages_Free会减少,HugePages_Rsvd也会减少!
HugePages_Total :对应内核参数 vm.nr_hugepages,也可以在运行中的系统上直接修改 /proc/sys/vm/nr_hugepages,修改的结果会立即影响空闲内存 MemFree的大小,因为HugePages在内核中独立管理,只要一经定义,无论是否被使用,都不再属于free memory。
AnonHugePages:它与/proc/meminfo的其他统计项有重叠,首先它被包含在AnonPages之中,而且在/proc/<pid>/smaps中也有单个进程的统计,与进程的RSS/PSS是有重叠的,如果用户进程用到了THP,进程的RSS/PSS也会相应增加,这与Hugepages是不同的。
LRU相关:LRU是Kernel的页面回收算法(Page Frame Reclaiming)。Page cache和所有用户进程的内存(kernel stack和huge pages除外)都在LRU lists上。
LRU lists包括如下几种,在/proc/meminfo中都有对应的统计值:
LRU_INACTIVE_ANON  –  对应 Inactive(anon)
LRU_ACTIVE_ANON  –  对应 Active(anon)
LRU_INACTIVE_FILE  –  对应 Inactive(file)
LRU_ACTIVE_FILE  –  对应 Active(file)
LRU_UNEVICTABLE  –  对应 Unevictable
注:
      Inactive list里的是长时间未被访问过的内存页,Active list里的是最近被访问过的内存页,LRU算法利用Inactive list和Active list可以判断哪些内存页可以被优先回收。
      1)括号中的 anon 表示匿名页(anonymous pages)。
      用户进程的内存页分为两种:file-backed pages(与文件对应的内存页),和anonymous pages(匿名页),比如进程的代码、映射的文件都是file-backed,而进程的堆、栈    都是不与文件相对应的、就属于匿名页。file-backed pages在内存不足的时候可以直接写回对应的硬盘文件里,称为page-out,不需要用到交换区(swap);而anonymous  pages在内存不足时就只能写到硬盘上的交换区(swap)里,称为swap-out。
       2)括号中的 file 表示 file-backed pages(与文件对应的内存页)。
        Unevictable LRU list上是不能pageout/swapout的内存页,包括VM_LOCKED的内存页、SHM_LOCK的共享内存页(又被统计在”Mlocked”中)、和ramfs。在unevictable list出现之前,这些内存页都在Active/Inactive lists上,vmscan每次都要扫过它们,但是又不能把它们pageout/swapout,这在大内存的系统上会严重影响性能,设计unevictable list的初衷就是避免这种情况,参见:https://www.kernel.org/doc/Documentation/vm/unevictable-lru.txt
LRU与/proc/meminfo中其他统计值的关系:
LRU中不包含HugePages_*。
LRU包含了 Cached 和 AnonPages。
Shmem:/proc/meminfo中的Shmem统计的内容包括:
             shared memory
             tmpfs和devtmpfs。
          注:所有tmpfs类型的文件系统占用的空间都计入共享内存,devtmpfs是/dev文件系统的类型,/dev/下所有的文件占用的空间也属于共享内存。可以用ls和du命令查看。如果文件在没有关闭的情况下被删除,空间仍然不会释放,shmem不会减小,可以用 “lsof -a +L1 /<mount_point>” 命令列出这样的文件。
           因为shared memory在内核中都是基于tmpfs实现的,参见:                        https://www.kernel.org/doc/Documentation/filesystems/tmpfs.txt
          也就是说它们被视为基于tmpfs文件系统的内存页,既然基于文件系统,就不算匿名页,所以不被计入/proc/meminfo中的AnonPages,而是被统计进了:
AnonPages:前面提到用户进程的内存页分为两种:file-backed pages(与文件对应的内存页),和anonymous pages(匿名页)。Anonymous pages(匿名页)的数量统计在/proc/meminfo的AnonPages中。
以下是几个事实,有助于了解Anonymous Pages:
所有page cache里的页面(Cached)都是file-backed pages,不是Anonymous Pages。”Cached”与”AnoPages”之间没有重叠。
          注:shared memory 不属于 AnonPages,而是属于Cached,因为shared memory基于tmpfs,所以被视为file-backed、在page cache里,前面说过。
               mmap private anonymous pages属于AnonPages(Anonymous Pages),而mmap shared anonymous pages属于Cached(file-backed pages),因为shared anonymous mmap也是基于tmpfs的。
              Anonymous Pages是与用户进程共存的,一旦进程退出,则Anonymous pages也释放,不像page cache即使文件与进程不关联了还可以缓存。
             AnonPages统计值中包含了Transparent HugePages (THP)对应的 AnonHugePages 。
 Mlocked:“Mlocked”统计的是被mlock()系统调用锁定的内存大小。被锁定的内存因为不能pageout/swapout,会从Active/Inactive LRU list移到Unevictable LRU list上。也就是说,当”Mlocked”增加时,”Unevictable”也同步增加,而”Active”或”Inactive”同时减小;当”Mlocked”减小的时候,”Unevictable”也同步减小,而”Active”或”Inactive”同时增加。
“Mlocked”并不是独立的内存空间,它与以下统计项重叠:LRU Unevictable,AnonPages,Shmem,Mapped等。
 Mapped:上面提到的用户进程的file-backed pages就对应着/proc/meminfo中的”Mapped”。Page cache中(“Cached”)包含了文件的缓存页,其中有些文件当前已不在使用,page cache仍然可能保留着它们的缓存页面;而另一些文件正被用户进程关联,比如shared libraries、可执行程序的文件、mmap的文件等,这些文件的缓存页就称为mapped。/proc/meminfo中的”Mapped”就统计了page cache(“Cached”)中所有的mapped页面。”Mapped”是”Cached”的子集。
因为Linux系统上shared memory & tmpfs被计入page cache(“Cached”),所以被attached的shared memory、以及tmpfs上被map的文件都算做”Mapped”。
进程所占的内存页分为anonymous pages和file-backed pages,理论上应该有:
【所有进程的PSS之和】 == 【Mapped + AnonPages】。
虽然两者很接近,却总是无法精确相等,我猜也许是因为进程始终在变化、采集的/proc/[1-9]*/smaps以及/proc/meminfo其实不是来自同一个时间点的缘故!

DirectMap(DirectMap4k/DirectMap2M/DirectMap1G)

     /proc/meminfo中的DirectMap所统计的不是关于内存的使用,而是一个反映TLB效率的指标。TLB(Translation Lookaside Buffer)是位于CPU上的缓存,用于将内存的虚拟地址翻译成物理地址,由于TLB的大小有限,不能缓存的地址就需要访问内存里的page table来进行翻译,速度慢很多。为了尽可能地将地址放进TLB缓存,新的CPU硬件支持比4k更大的页面从而达到减少地址数量的目的, 比如2MB,4MB,甚至1GB的内存页,视不同的硬件而定。”DirectMap4k”表示映射为4kB的内存数量, “DirectMap2M”表示映射为2MB的内存数量,以此类推。所以DirectMap其实是一个反映TLB效率的指标。

用户进程的内存主要有三种统计:
围绕LRU进行统计
    【(Active + Inactive + Unevictable) + (HugePages_Total * Hugepagesize)】
      2.   围绕Page Cache进行统计
    当SwapCached为0的时候,用户进程的内存总计如下:
    【(Cached + AnonPages + Buffers) + (HugePages_Total * Hugepagesize)】
    当SwapCached不为0的时候,以上公式不成立,因为SwapCached可能会含有Shmem,而Shmem本来被含在Cached中,一旦swap-out就从Cached转移到了SwapCached,可是    我们又不能把SwapCached加进上述公式中,因为SwapCached虽然不与Cached重叠却与AnonPages有重叠,它既可能含有Shared memory又可能含有Anonymous Pages。
      3.  围绕RSS/PSS进行统计
    把/proc/[1-9]*/smaps 中的 Pss 累加起来就是所有用户进程占用的内存,但是还没有包括Page Cache中unmapped部分、以及HugePages,所以公式如下:
    ΣPss + (Cached – mapped) + Buffers + (HugePages_Total * Hugepagesize)
参考:http://linuxperf.com/?p=142

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值