NotePublic/Software/System/Linux/Modules/Memory/Meminfo_文件详解.md

262 lines
9.8 KiB
Markdown
Raw Normal View History

# Meminfo 文件详解
我们可以从 /proc/meminfo 中查看内核使用内存情况的各种信息。一个 /proc/meminfo 的内容看起来是这样的:
```bash
$ cat /proc/meminfo |nl
1 MemTotal: 3814108 kB
2 MemFree: 111908 kB
3 MemAvailable: 394844 kB
4 Buffers: 22976 kB
5 Cached: 291436 kB
6 SwapCached: 15480 kB
7 Active: 1634948 kB
8 Inactive: 784896 kB
9 Active(anon): 1487400 kB
10 Inactive(anon): 474008 kB
11 Active(file): 147548 kB
12 Inactive(file): 310888 kB
13 Unevictable: 0 kB
14 Mlocked: 0 kB
15 SwapTotal: 8388604 kB
16 SwapFree: 8238844 kB
17 Dirty: 22280 kB
18 Writeback: 0 kB
19 AnonPages: 2103892 kB
20 Mapped: 1262612 kB
21 Shmem: 81684 kB
22 Slab: 99048 kB
23 SReclaimable: 53432 kB
24 SUnreclaim: 45616 kB
25 KernelStack: 8352 kB
26 PageTables: 24152 kB
27 NFS_Unstable: 0 kB
28 Bounce: 0 kB
29 WritebackTmp: 0 kB
30 CommitLimit: 10295656 kB
31 Committed_AS: 6235812 kB
32 VmallocTotal: 34359738367 kB
33 VmallocUsed: 0 kB
34 VmallocChunk: 0 kB
35 HardwareCorrupted: 0 kB
36 AnonHugePages: 0 kB
37 ShmemHugePages: 0 kB
38 ShmemPmdMapped: 0 kB
39 HugePages_Total: 0
40 HugePages_Free: 0
41 HugePages_Rsvd: 0
42 HugePages_Surp: 0
43 Hugepagesize: 2048 kB
44 DirectMap4k: 106112 kB
45 DirectMap2M: 3858432 kB
```
可以看出,这里的内核信息特别多,有些含义很难理解。
下面就来尝试解释一下这些行的意义:
## MemTotal
总共安装的物理内存容量
## MemFree
当前空闲的内存量
## MemAvailable
## Buffers / Cached
buffers + cached的值就是可以使用的磁盘告诉缓存的大小。
buffers + cached = Active(file) + Inactive(file) + Shmem
## SwapCached
记录在交换缓存上的内容容量。
所谓交换缓存是指,在换入某个内存页之后,物理磁盘上的交换空间依然保留同样的数据,这样的内存页会记录在"交换缓存"的列表上。 这样的好处在于,当需要再次换出记录在交换缓存中的的内存页时,可以直接使用交换分区中保存的内容,而无需将内存再次写入交换空间。
当该交换空间上的其他数据被换出,或是换入内存中的数据被改写,则交换缓存上的记录会被清空。
## Active
等于Active(anon) + Active(file)的和
## Inactive
等于Inactive(anon) + Inactive(file)的和
## Active(anon) / Inactive(anon) / Active(file) / Inactive(file)
括号中为anon的内存为匿名内存括号中为file的内存为file-backed内存这两个内存的区别在于物理内存的内容是否与物理磁盘上的文件相关联。
其中匿名内存就是进程中堆上分配的内存是用malloc分配的内存。
而file-backed内存为磁盘高速缓存的内存空间和“文件映射(将物理磁盘上的文件内容与用户进程的逻辑地址直接关联)”的内存空间,其中的内容与物理磁盘上的文件相对应。
而Active和Inactive的区别在于内存空间中是否包含最近被使用过的数据。当物理内存不足不得不释放正在使用的内存空间时会优先释放Inactive的内存空间。
Linux内核中使用4类LRU表来分别记录对应的这4类内存页,内存页一般以4K为一页。
## Unevictable
有些内存页是不能被释放的这些内存页不能放在LRU表中而是记录到Unevictable标中
## Mlocked
## SwapTotal
交换空间的总大小
## SwapFree
交换空间的剩余容量
## Dirty
脏数据,在磁盘缓冲区中尚未写入物理磁盘的内存大小
## Writeback
## AnonPages
Linux内核中存在一个rmap(reverse mapping)机制,负责管理匿名内存中每一个物理内存页映射到哪个进程的哪个逻辑地址这样的信息。 这个rmap中记录的内存页总和就是AnonPages的值。
## Mapped
## Shmem
tmpfs所使用的内存.
tmpfs即利用物理内存来提供RAM磁盘的功能。在tmpfs上保存文件时文件系统会暂时将它们保存到磁盘高速缓存上因此它是属于磁盘高速缓存对应的"buffers+cached"一类。 但是由于磁盘上并没有与之对应的内容因此它并记录在File-backed内存对应的LRU列表上而是记录在匿名内存的LRU表上。 这就是 buffers + cached = Active(file) + Inactive(file) + Shmem 公式的由来
## Slab
由"Slab分配器"分配的总量。Slab分配器针对一些经常分配并释放的对象(如进程描述符)统计各种数据类型的汇总信息然后为每种数据类型创建多个由多个内存页组成的Slab(这些Slab组成一个Slab列表)。 再在Slab内部划分成一个个相应数据类型的对象。
当内核要使用某种类型的数据结构时就从对应的slab列表中分配一个对象出去而当要释放时将其重新保存在Slab列表中从而避免内存碎片。
当可供使用的对象不足时会使用空闲的内存页来创建并添加新的Slab到对应对象的Slab列表中。 相反若Slab中所有对象都被内核回收即所有对象都未使用时根据需要也可以回收Slab释放成空闲内存。
从 /proc/slabinfo 中我们可以查看每个Slab的信息
```bash
$ sudo cat /proc/slabinfo |head
slabinfo - version: 2.1
# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
nf_conntrack 27 72 320 12 1 : tunables 0 0 0 : slabdata 6 6 0
ovl_inode 46 46 688 23 4 : tunables 0 0 0 : slabdata 2 2 0
fuse_request 40 40 400 20 2 : tunables 0 0 0 : slabdata 2 2 0
fuse_inode 19 19 832 19 4 : tunables 0 0 0 : slabdata 1 1 0
xfs_dqtrx 0 0 528 15 2 : tunables 0 0 0 : slabdata 0 0 0
xfs_rui_item 0 0 672 12 2 : tunables 0 0 0 : slabdata 0 0 0
xfs_rud_item 0 0 152 26 1 : tunables 0 0 0 : slabdata 0 0 0
xfs_ili 4486 4488 168 24 1 : tunables 0 0 0 : slabdata 187 187 0
```
其中:
* name对象名称
* active_objs处于活跃状态的对象个数
* num_objsslab列表中的总对象数量
* objperslab一个slab中包含的对象个数
* pageperslab每个slab占用的内存页数
* num_slabsslab列表中slab的个数
* active_slabs处于活跃状态的slab个数
## SReclaimable
不存在活跃对象可以回收的Slab容量
## SUnreclaim
对象处于活跃状态不能被回收的Slab容量
## KernelStack
KernelStack是内核代码使用的堆栈区域。
由于Linux内核中用户进程在运行过程中需要不断切换因此内核需要为每个用户进程都设置各自的堆栈区域。 因此每启动一个新进程KernelStack的值都会增加。
## PageTables
PageTables就是页表用于存储各个用户进程的逻辑地址和物理地址的变换关系它本身也是一个内存区域。
## NFS_Unstable
## Bounce
## WritebackTmp
## CommitLimit
## Committed_AS
## VmallocTotal
Linux使用内存时除了使用Slab中配置的对象外还能直接将空闲内存页映射到逻辑地址上。
这个容量指的是,理论上内核内部可以用来映射的逻辑地址的范围。这个值非常大,但并非实际使用的物理内存
## VmallocUsed
实际上Linux将空闲内存页映射到逻辑地址上的容量。
值得说明的是,这个容量除了物理内存上所作的映射外,也包括诸如视频卡这样的外部设备内存所作的映射,这类映射叫做"ioremap"
我们可以通过 /proc/vmallocainfo 查看VmallocUsed中包含内存区域的详情
```bash
$ cat /proc/vmallocinfo |head
0x000000008088114a-0x000000001aecb69b 8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6bd000 ioremap
0x000000001aecb69b-0x0000000086f9fed7 8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e4000 ioremap
0x0000000086f9fed7-0x000000006fbc598c 8192 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e2000 ioremap
0x000000006fbc598c-0x00000000636e4cf9 12288 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6e2000 ioremap
0x00000000636e4cf9-0x000000005464ab58 8192 hpet_enable+0x34/0x2c1 phys=0x00000000fed00000 ioremap
0x000000005464ab58-0x00000000396cc741 12288 alloc_large_system_hash+0x194/0x257 pages=2 vmalloc N0=2
0x00000000396cc741-0x0000000038ec28d8 8192 bpf_prog_alloc+0x40/0xb0 pages=1 vmalloc N0=1
0x0000000038ec28d8-0x000000002f686ade 65536 acpi_os_map_iomem+0x14c/0x180 phys=0x00000000bf6bd000 ioremap
0x000000002f686ade-0x00000000fee69f16 4198400 alloc_large_system_hash+0x194/0x257 pages=1024 vmalloc vpages N0=1024
0x00000000fee69f16-0x00000000362aad15 2101248 alloc_large_system_hash+0x194/0x257 pages=512 vmalloc N0=512
```
其中
* 第一列为逻辑地址的范围
* 第二列为容量,以字节为单位
* 最后一列若为ioremap说明该映射为ioremap
所以要计算除ioremap外物理内存的映射量可以这么计算
```bash
$ sudo cat /proc/vmallocinfo |grep -v "ioremap" |awk '{total=total+$2};END{print total}'
107110400
```
## VmallocChunk
// TODO:
## HardwareCorrupted
## AnonHugePages
## ShmemHugePages
## ShmemPmdMapped
## HugePages_Total
## HugePages_Free
## HugePages_Rsvd
## HugePages_Surp
## Hugepagesize
## DirectMap4k
## DirectMap2M