proc下meminfo的细节
续接十年前总结的前文linux的内存管理介绍
最近遇到了Serverless平台的管理节点上报内存不准确的问题,导致调度误判从而大量oom,所以不同于前文对meminfo一笔带过,需要对meminfo做一个系统的深入了解,并对其内容做一个分类,搞清楚存在的相互联系
首先贴一个/proc/meminfo
的数据,可以看到,有49项,非常复杂
1 | MemTotal: 1950928 kB |
前置知识
内核内存分配函数与内存黑洞
alloc_pages/__get_free_page:以页为单位分配,是全部内存分配的基础
kmalloc
以字节为单位分配虚拟地址连续的小块内存块
很接近我们使用的malloc,只是内核使用,所以有个k前缀
他是基于slab allocator的
slab
提供内存缓存管理,支持对象缓存功能,优化内存碎片,以提高内存重用性和性能
参见/proc/meminfo中的Slab/SReclaimable/SUnreclaim
vmalloc
以字节为单位分配虚拟地址连续的大块内存块
和kmalloc的区别就在于为了分配大块的内存块,把物理上不连续的页转换为虚拟地址空间上连续的页,必须专门建立页表项,而且因为它们物理上是不连续的,所以必须一个一个进行映射,这会导致比直接内存映射大得多的 TLB 抖动。尽管在某些情况下才需要物理上的连续内存块,但出于性能的考虑,很多内核代码都使用
kmalloc()
。除非在不得已时才使用vmalloc()
,比如动态装载模块时,需要获得大块内存。参见/proc/meminfo中的VmallocUsed 和 /proc/vmallocinfo
而alloc_pages作为一个非常底层的接口,是没有自动统计的,因此这一部分使用的内存会进入内存黑洞,这个无法追踪
MemTotal,MemFree,MemAvailable
这个很常见,free -m也能看到
其中MemTotal不是真实的整机容量,使用dmest -T|grep reserved
可以看到内核预留了一些容量
1 | Memory: 261120K/2013488K available (12292K kernel code, 2152K rwdata, 3852K rodata, 2408K init, 6468K bss, 93928K reserved, 0K cma-reserved) |
MemFree就是剩下完全没有使用的内存,但是并不是最终的可用内存,因为有一部分内存是可以page out
的,所以有一个预估的MemAvailable
内核使用
Slab,SReclaimable,SUnreclaim
这个非常容易理解,Slab的总量,可回收的和不可回收的
VmallocTotal,VmallocUsed,VmallocChunk
出于性能原因,这些字段在 Linux 4.4 中被清零。与 glibc 链接的程序在启动时会读取此文件,并且它会造成可衡量的影响。
mm: get rid of 'vmalloc_info' from /proc/meminfo,Linux本人在本文说道
but the whole vmalloc information of of rather dubious value to begin with, and people who actually want to know what the situation is wrt the vmalloc area should just look at the much more complete /proc/vmallocinfo instead.
但整个 vmalloc 信息的价值一开始就相当可疑,而那些真正想知道 vmalloc 区域情况的人应该查看更完整的 /proc/vmallocinfo
vmallocinfo的信息数据如下,其中可以看到每个vmalloc的调用者:
1 | ~ grep vmalloc /proc/vmallocinfo |head |
所以统计vmalloc的使用量是:
1 | ~ grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}' |
没什么卵用的冷知识:lsmod
第二列就是内核模块所占内存的大小,但是是按page算的,1个字节也会取整到1个page,具体可以看内核模块
HardwareCorrupted
当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用
PageTables
Page Table用于将内存的虚拟地址翻译成物理地址,随着内存地址分配得越来越多,Page Table会增大,/proc/meminfo中的PageTables统计了Page Table所占用的内存大小
区分以下概念:
- Page Cache:用于缓存磁盘上的文件数据,以加速文件读写操作
- Page Frame(页帧):物理内存的最小单位是page frame,每个物理页对应一个描述符(struct page),在内核的引导阶段就会分配好。只会随着物理内存的变大而引导时变大,不会动态增长。
KernelStack
每一个用户线程都会分配一个kernel stack(内核栈),内核栈虽然属于线程,但用户态的代码不能访问,只有通过系统调用(syscall)、自陷(trap)或异常(exception)进入内核态的时候才会用到
Bounce
老设备用,已经很少见了
用户进程使用
参考资料:
linux内核中的各种内存分配函数:kmalloc、vmalloc、slab、__get_free_pages、mempoll_alloc