曾文斌: /proc/meminfo之谜完全揭秘

本文详细探讨了Linux系统中/proc/meminfo内存统计的各项指标,包括MemTotal、MemFree、MemAvailable等,以及内存黑洞现象。通过分析内核内存和用户进程内存的使用,如SLAB、VmallocUsed、KernelStack等,揭示了内存分配的细节。文章还讨论了直接映射、脏页、Active和Inactive的区别,并解释了为何某些内存统计不相等的原因。
摘要由CSDN通过智能技术生成

/proc/meminfo是了解Linux系统内存使用状况的主要接口,我们最常用的”free”、”vmstat”等命令就是通过它获取数据的
/proc/meminfo所包含的信息比”free”等命令要丰富得多,然而真正理解它并不容易,
比如我们知道”Cached”统计的是文件缓存页,manpage上说是“In-memory cache for files read from the disk (the page cache)
那为什么它不等于[Active(file)+Inactive(file)]
AnonHugePagesAnonPagesHugePages_Total有什么联系和区别?很多细节在手册中并没有讲清楚,本文对此做了一点探究。

负责输出/proc/meminfo的源代码是:
fs/proc/meminfo.c : meminfo_proc_show()

MemTotal:        3809036 kB
MemFree:          282012 kB
MemAvailable:     865620 kB
Buffers:               0 kB
Cached:           854972 kB
SwapCached:       130900 kB
Active:          1308168 kB
Inactive:        1758160 kB
Active(anon):    1010416 kB
Inactive(anon):  1370480 kB
Active(file):     297752 kB
Inactive(file):   387680 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:       4063228 kB
SwapFree:        3357108 kB
Dirty:                 0 kB
Writeback:             0 kB
AnonPages:       2104412 kB
Mapped:            40988 kB
Shmem:            169540 kB
Slab:             225420 kB
SReclaimable:     134220 kB
SUnreclaim:        91200 kB
KernelStack:        5936 kB
PageTables:        35628 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:     5967744 kB
Committed_AS:    5626436 kB
VmallocTotal:   34359738367 kB
VmallocUsed:      351900 kB
VmallocChunk:   34359363652 kB
HardwareCorrupted:     0 kB
AnonHugePages:    139264 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
DirectMap4k:      204484 kB
DirectMap2M:     3915776 kB

MemTotal

系统从加电开始到引导完成,firmware/BIOS要保留一些内存,kernel本身要占用一些内存,最后剩下可供kernel支配的内存就是MemTotal。这个值在系统运行期间一般是固定不变的。可参阅解读DMESG中的内存初始化信息。

MemFree

表示系统尚未使用的内存。[MemTotal-MemFree]就是已被用掉的内存。

MemAvailable

有些应用程序会根据系统的可用内存大小自动调整内存申请的多少,所以需要一个记录当前可用内存数量的统计值,MemFree并不适用,因为MemFree不能代表全部可用的内存
系统中有些内存虽然已被使用但是可以回收的,比如cache/bufferslab都有一部分可以回收,所以这部分可回收的内存加上MemFree才是系统可用的内存,即MemAvailable
/proc/meminfo中的MemAvailable是内核使用特定的算法估算出来的,要注意这是一个估计值,并不精确。

内存黑洞

追踪Linux系统的内存使用一直是个难题,很多人试着把能想到的各种内存消耗都加在一起,kernel textkernel modulesbuffercacheslabpage tableprocess RSS…等等,却总是与物理内存的大小对不上,这是为什么呢?

因为Linux kernel并没有滴水不漏地统计所有的内存分配,kernel动态分配的内存中就有一部分没有计入/proc/meminfo中。

我们知道,Kernel的动态内存分配通过以下几种接口:

  • alloc_pages/__get_free_page: 以页为单位分配
  • vmalloc: 以字节为单位分配虚拟地址连续的内存块
  • slab allocator
  • kmalloc: 以字节为单位分配物理地址连续的内存块,它是以slab为基础的,使用slab层的general caches — 大小为2^n,名称是kmalloc-32kmalloc-64等(在老kernel上的名称是size-32size-64等)。

通过slab层分配的内存会被精确统计,可以参见/proc/meminfo中的slab/SReclaimable/SUnreclaim

通过vmalloc分配的内存也有统计,参见/proc/meminfo中的VmallocUsed/proc/vmallocinfo(下节中还有详述);

而通过alloc_pages分配的内存不会自动统计,除非调用alloc_pages的内核模块或驱动程序主动进行统计,否则我们只能看到free memory减少了,但从/proc/meminfo中看不出它们具体用到哪里去了。
比如在VMware guest上有一个常见问题,就是VMWare ESX宿主机会通过guest上的Balloon driver(vmware_balloon module)占用guest的内存
有时占用得太多会导致guest无内存可用,这时去检查guest/proc/meminfo只看见MemFree很少
但看不出内存的去向,原因就是Balloon driver通过alloc_pages分配内存,没有在/proc/meminfo中留下统计值,所以很难追踪。

内存都到哪里去了?

使用内存的,不是kernel就是用户进程,下面我们就分类讨论。
注:page cache比较特殊,很难区分是属于kernel还是属于进程,其中被进程mmap的页面自然是属于进程的了,而另一些页面没有被mapped到任何进程,那就只能算是属于kernel了。

1. 内核

内核所用内存的静态部分,比如内核代码页描述符等数据在引导阶段就分配掉了,并不计入MemTotal里,而是算作Reserved(在dmesg中能看到)。
而内核所用内存的动态部分,是通过上文提到的几个接口申请的,其中通过alloc_pages申请的内存有可能未纳入统计,就像黑洞一样。

下面讨论的都是/proc/meminfo中所统计的部分。

1.1 SLAB

通过slab分配的内存被统计在以下三个值中:
SReclaimable: slab中可回收的部分。调用kmem_getpages()时加上SLAB_RECLAIM_ACCOUNT标记,表明是可回收的,计入SReclaimable,否则计入SUnreclaim
SUnreclaim:slab中不可回收的部分
Slab:slab中所有的内存,等于以上两者之和

1.2 VmallocUsed

通过vmalloc分配的内存都统计在/proc/meminfoVmallocUsed值中,但是要注意这个值不止包括了分配的物理内存,还统计了VM_IOREMAPVM_MAP等操作的值
譬如VM_IOREMAP是把IO地址映射到内核空间、并未消耗物理内存,所以我们要把它们排除在外。
从物理内存分配的角度,我们只关心VM_ALLOC操作,这可以从/proc/vmallocinfo中的vmalloc记录看到:

# grep vmalloc /proc/vmallocinfo
...
0xffffc90004702000-0xffffc9000470b000   36864 alloc_large_system_hash+0x171/0x239 pages=8 vmalloc N0=8
0xffffc9000470b000-0xffffc90004710000   20480 agp_add_bridge+0x2aa/0x440 pages=4 vmalloc N0=4
0xffffc90004710000-0xffffc90004731000  135168 raw_init+0x41/0x141 pages=32 vmalloc N0=32
0xffffc90004736000-0xffffc9000473f000   36864 drm_ht_create+0x55/0x80 [drm] pages=8 vmalloc N0=8
0xffffc90004744000-0xffffc90004746000    8192 dm_table_create+0x9e/0x130 [dm_mod] pages=1 vmalloc N0=1
0xffffc90004746000-0xffffc90004748000    8192 dm_table_create+0x9e/0x130 [dm_mod] pages=1 vmalloc N0=1
...
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值