Linux中与内存相关的节点

作者 by adtxl / 2021-12-09 / 暂无评论 / 516 个足迹

1. /proc/meminfo

linux系统中/proc/meminfo这个文件用来记录了系统内存使用的详细情况。其中top,free命令中的数据是通过这个文件中的信息计算并按照特定的格式进行显示。

console:/ # cat /proc/meminfo

MemTotal:        1323096 kB     // 所有内存(RAM)大小,减去一些预留空间和内核的大小。
MemFree:          164004 kB     // 完全没有用到的物理内存,lowFree+highFree
// 在不使用交换空间的情况下,启动一个新的应用最大可用内存的大小
// 系统中有些内存虽然已被使用但是可以回收的,比如cache/buffer、slab都有一部分可以回收,所以MemFree不能代表全部可用的内存,
// 这部分可回收的内存加上MemFree才是系统可用的内存,即:MemAvailable≈MemFree+Buffers+Cached
// 计算方式:MemFree+Active(file)+Inactive(file)-(watermark+min(watermark,Active(file)+Inactive(file)/2))
MemAvailable:     629700 kB
// 块设备所占用的缓存页,包括:直接读写块设备以及文件系统元数据(metadata),比如superblock使用的缓存页。
Buffers:            7036 kB
Cached:           495616 kB     // 表示普通文件数据所占用的缓存页。

// 被高速缓冲存储器(cache memory)用的交换空间的大小,已经被交换出来的内存,但仍然被存放在swapfile中。用来在需要的时候很快的被替换而不需要再次打开I/O端口
// swap cache中包含的是被确定要swapping换页,但是尚未写入物理交换区的匿名内存页。
// 那些匿名内存页,比如用户进程malloc申请的内存页是没有关联任何文件的,如果发生swapping换页,这类内存会被写入到交换区。
SwapCached:            0 kB
// active包含active anon和active file,在活跃使用中的缓冲或高速缓冲存储器页面文件的大小,除非非常必要否则不会被移作他用
Active:           597540 kB
// inactive包含inactive anon和inactive file,在不经常使用中的缓冲或高速缓冲存储器页面文件的大小,可能被用于其他途径
Inactive:         289768 kB

// 活跃的与文件无关的内存(比如进程的堆栈,用malloc申请的内存)(anonymous pages),anonymous pages在发生换页时,是对交换区进行读/写操作
Active(anon):     350804 kB
// 非活跃的与文件无关的内存(比如进程的堆栈,用malloc申请的内存)
Inactive(anon):    39764 kB
// 活跃的与文件关联的内存(比如程序文件、数据文件所对应的内存页)(file-backed pages) File-backed pages在发生换页(page-in或page-out)时,是从它对应的文件读入或写出
Active(file):     246736 kB
// 非活跃的与文件关联的内存(比如程序文件、数据文件所对应的内存页)
Inactive(file):   250004 kB
// The amount of memory, in kibibytes, discovered by the pageout code,
// that is not evictable because it is locked into memory by user programs.
Unevictable:        3564 kB
// The total amount of memory, in kibibytes, that is not evictable because it is locked into memory by user programs.
Mlocked:            3564 kB
// 可用的swap空间的总的大小(swap分区在物理内存不够的情况下,把硬盘空间的一部分释放出来,以供当前程序使用)
SwapTotal:        102396 kB
SwapFree:         102396 kB     // 当前剩余的swap的大小
Dirty:                 8 kB     // 等待被写回到磁盘的内存大小
Writeback:             0 kB     // 正在被写回到磁盘的内存大小
AnonPages:        388332 kB     // 未映射页的内存大小
Mapped:           370680 kB     // 设备和文件等映射的大小
Shmem:              3784 kB     // The total amount of memory, in kibibytes, used by shared memory (shmem) and tmpfs.
// Kernel allocations that the kernel will attempt to reclaim under memory pressure.
// Includes SReclaimable (below), and other direct allocations with a shrinker.
KReclaimable:      58644 kB
Slab:             121732 kB     // 内核数据结构slab的大小
SReclaimable:      58644 kB     // 可回收的slab的大小
SUnreclaim:        63088 kB     // 不可回收的slab的大小
KernelStack:       17056 kB     // 常驻内存,每一个用户线程都会分配一个kernel stack(内核栈)
PageTables:        28504 kB     // 管理内存分页页面的索引表的大小
NFS_Unstable:          0 kB     // 不稳定页表的大小
// 有些老设备只能访问低端内存,比如16M以下的内存,当应用程序发出一个I/O 请求,DMA的目的地址却是高端内存时(比如在16M以上),
// 内核将在低端内存中分配一个临时buffer作为跳转,把位于高端内存的缓存数据复制到此处。
// 这种额外的数据拷贝被称为“bounce buffering”,会降低I/O 性能
// The amount of memory, in kibibytes, used for the block device "bounce buffers".
Bounce:                0 kB
// Memory used by FUSE for temporary writeback buffers
WritebackTmp:          0 kB
// 根据超额分配比率('vm.overcommit_ratio'),这是当前在系统上分配可用的内存总量,
// 这个限制只是在模式2('vm.overcommit_memory')时启用。
// CommitLimit用以下公式计算:CommitLimit =('vm.overcommit_ratio'*物理内存/100)+交换
// 例如,在具有1G物理RAM和7G swap的系统上,当`vm.overcommit_ratio` = 30时 CommitLimit =7.3G
CommitLimit:      763944 kB

// 目前在系统上分配的内存量。是所有进程申请的内存的总和,即时所有申请的内存没有被完全使用,例如一个进程申请了1G内存,仅仅使用了300M,但是这1G内存的申请已经被 "committed"给了VM虚拟机,进程可以在任何时间使用。如果限制在模式2('vm.overcommit_memory')时启用,分配超出CommitLimit内存将不被允许
Committed_AS:   18004156 kB
VmallocTotal:   263061440 kB    // Vmalloc内存区的大小
VmallocUsed:       31860 kB     // 已用Vmalloc内存区的大小
VmallocChunk:          0 kB     // vmalloc区可用的连续最大快的大小
// percpu 为所有已定义的per-cpu变量分配副本空间,静态定义的per-cpu变量越多,这个区域越大。
Percpu:             3456 kB
// 当系统检测到内存的硬件故障时,会把有问题的页面删除掉,不再使用,
// /proc/meminfo中的HardwareCorrupted统计了删除掉的内存页的总大小。相应的代码参见 mm/memory-failure.c: memory_failure()。
HardwareCorrupted:     0 kB
CmaTotal:         380928 kB     // CMA内存总量
CmaFree:          129412 kB     // 可用CMA内存
HugePages_Total:       0        // 预留的大页内存总量
HugePages_Free:        0        // 空闲的大页内存
HugePages_Rsvd:        0        // 已经被应用程序分配但尚未使用的大页内存
HugePages_Surp:        0        // 初始大页数与修改配置后大页数的差值
Hugepagesize:       2048 kB     // 单个大页内存的大小
// is the total amount of memory (in kB), consumed by huge pages of all sizes.
// If huge pages of different sizes are in use, this number will exceed HugePages_Total * Hugepagesize. T
Hugetlb:               0

2. /proc/vmallocinfo

vmalloc 用于在内核中分配虚拟地址空间连续的内存,/proc/vmallocinfo 展示了整个vmalloc区间(VMALLOC_END - VMALLOC_START)中已经分配的虚拟地址空间信息。
第一列是区域虚拟地址起点终点,第二列是区域的大小,第三列是调用者,第四列是对应的页面数量(可选),第五列是物理地址(可选),第六列是区域类型(可选),最后节点序号(可选)。
下面是可选信息的含义

optional information
pages=nr number of pages
phys=addr if a physical address was specified
ioremap I/O mapping (ioremap() and friends)
vmalloc vmalloc() area
vmap vmap()ed pages
user VM_USERMAP area
vpages buffer for pages pointers was vmalloced (huge area)
N<node>=nr (Only on NUMA kernels) Number of pages allocated on memory node <node>

通过vmalloc分配了多少内存,可以统计/proc/vmallocinfo中的vmalloc记录,例如:

# grep vmalloc /proc/vmallocinfo | awk '{total+=$2}; END {print total}'

0xffffa86580000000-0xffffa86580005000   20480 irq_init_percpu_irqstack+0xcf/0x100 vmap
0xffffa86580005000-0xffffa86580007000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc07000 ioremap
0xffffa86580007000-0xffffa86580009000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbb1e000 ioremap
0xffffa86580009000-0xffffa8658000b000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc0c000 ioremap
0xffffa8658000c000-0xffffa8658000f000   12288 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc0a000 ioremap
0xffffa8658000f000-0xffffa86580011000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc09000 ioremap
0xffffa86580011000-0xffffa86580013000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc08000 ioremap
0xffffa86580013000-0xffffa86580015000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc06000 ioremap
0xffffa86580015000-0xffffa86580017000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbc05000 ioremap
0xffffa86580017000-0xffffa86580019000    8192 intel_pstate_init+0x328/0x433 pages=1 vmalloc N0=1
0xffffa86580019000-0xffffa8658001b000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbbe4000 ioremap
0xffffa8658001b000-0xffffa8658001d000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbbe3000 ioremap
0xffffa8658001d000-0xffffa8658001f000    8192 acpi_os_map_iomem+0x17c/0x1b0 phys=0x00000000cbbde000 ioremap
......

3. /proc/slabinfo

显示slab内存使用情况

为了满足内核对小内存块的需要,Linux系统采用了一种被称为slab分配器的技术。Slab分配器的实现相当复杂,但原理不难,其核心思想就是“存储池”的运用。内存片段(小块内存)被看作对象,当被使用完后,并不直接释放而是被缓存到“存储池”里,留做下次使用,这无疑避免了频繁创建与销毁对象所带来的额外负载。SLAB分配器使得一个页面内众多小块内存可独立被分配使用,避免了内部分片,节约了空闲内存 。

130|console:/ $ cat /proc/slabinfo
slabinfo - version: 2.1
# name            <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab> : tunables <limit> <batchcount> <sharedfactor> : slabdata <active_slabs> <num_slabs> <sharedavail>
zs_handle           1024   1024      8  512    1 : tunables    0    0    0 : slabdata      2      2      0
ext4_groupinfo_4k    104    104    152   26    1 : tunables    0    0    0 : slabdata      4      4      0
fsverity_info          0      0    256   16    1 : tunables    0    0    0 : slabdata      0      0      0
PINGv6                 0      0   1216   26    8 : tunables    0    0    0 : slabdata      0      0      0
RAWv6                 78     78   1216   26    8 : tunables    0    0    0 : slabdata      3      3      0
UDPv6                 96     96   1344   24    8 : tunables    0    0    0 : slabdata      4      4      0
tw_sock_TCPv6         31     31    264   31    2 : tunables    0    0    0 : slabdata      1      1      0
request_sock_TCPv6      0      0    336   24    2 : tunables    0    0    0 : slabdata      0      0      0
TCPv6                 39     39   2496   13    8 : tunables    0    0    0 : slabdata      3      3      0
nf_conntrack         875    875    320   25    2 : tunables    0    0    0 : slabdata     35     35      0
ashmem_area_cache    104    104    312   26    2 : tunables    0    0    0 : slabdata      4      4      0

4. /proc/buddyinfo

proc/buddyinfo是linuxbuddy系统管理物理内存的debug信息,Buddyinfo会告诉你,你可以安全地分配多大的区域,或者为什么以前的分配失败。在Linux中使用buddy算法解决物理内存的外碎片问题,其把所有空闲的内存,以2的幂次方的形式,分成11个块链表,分别对应为1、2、4、8、16、32、64、128、256、512、1024个页块。而Linux支持NUMA技术,对于NUMA设备,NUMA系统的结点通常是由一组CPU和本地内存组成,每一个节点都有相应的本地内存,因此buddyinfo 中的Node0表示节点ID;而每一个节点下的内存设备,又可以划分为多个内存区域(zone),因此下面的显示中,对于Node0的内存,又划分类DMA、Normal、HighMem区域。而后面则是表示空闲的区域。

每列表示某种特定页面的可用大小。此处以DMA32区域进行分析,第一列值为1186,表示有1186块可用的大小为20*PAGE_SIZE有表示当前系统中DMA32区域第二列值为835,表示当前系统中DMA32区域,可用的连续两页的内存大小为835*21*PAGE_SIZE;第三列值为712,表示当前系统中DMA32区域,可用的连续四页的内存大小为712*22*PAGE_SIZE

console:/ # cat /proc/buddyinfo
Node 0, zone    DMA32   1186    835    712    534    287    134     54     19      1      2     28
Node 0, zone      DMA      0      4      5      4      4      3 ...
Node 0, zone   Normal      1      0      0      1    101      8 ...
Node 0, zone  HighMem      2      0      0      1      1      0 ...

5. /proc/vmstat

/proc/vmstat文件显示的时从内核导出的虚拟内存的统计信息。

xxx:/ # cat /proc/vmstat

nr_free_pages 40842
nr_zone_inactive_anon 6126
nr_zone_active_anon 91359
nr_zone_inactive_file 66745
nr_zone_active_file 57649
nr_zone_unevictable 893
nr_zone_write_pending 9
nr_mlock 893
nr_page_table_pages 7085
nr_kernel_stack 16832
nr_bounce 0
nr_zspages 3
nr_free_cma 33065
nr_inactive_anon 6126
nr_active_anon 91359
nr_inactive_file 66745
nr_active_file 57649
nr_unevictable 893
nr_slab_reclaimable 14824
nr_slab_unreclaimable 16408
nr_isolated_anon 0
nr_isolated_file 0
workingset_refault 873
workingset_activate 873
workingset_restore 0
workingset_nodereclaim 0
nr_anon_pages 96907
nr_mapped 92157
nr_file_pages 125876
nr_dirty 9
nr_writeback 0
nr_writeback_temp 0
nr_shmem 951
nr_shmem_hugepages 0
nr_shmem_pmdmapped 0
nr_anon_transparent_hugepages 0
nr_unstable 0
nr_vmscan_write 0
nr_vmscan_immediate_reclaim 1
nr_dirtied 5282
nr_written 5220
nr_kernel_misc_reclaimable 0
nr_unreclaimable_pages 0
nr_ion_heap 0
nr_ion_heap_pool 0
nr_dirty_threshold 31497
nr_dirty_background_threshold 15729
pgpgin 550951       // 从启动到现在读入的内存页数
pgpgout 32348
pgpgoutclean 11865
pswpin 0        // 从启动到现在读入的交换分区页数
pswpout 0
pgalloc_dma32 790529
pgalloc_normal 0
pgalloc_movable 0
allocstall_dma32 0
allocstall_normal 0
allocstall_movable 0
pgskip_dma32 0
pgskip_normal 0
pgskip_movable 0
pgfree 869420       // 从启动到现在释放的页数
pgactivate 62528        // 从启动到现在激活的页数
pgdeactivate 11314      // 从启动到现在去激活的页数
pglazyfree 0
pgfault 842874      // 从启动到现在二级页面错误数
pgmajfault 3991     // 从启动到现在一级页面错误数
pglazyfreed 0
pgrefill 12612
pgsteal_kswapd 11985
pgsteal_direct 0
pgscan_kswapd 44067
pgscan_direct 0
pgscan_direct_throttle 0
pginodesteal 0
slabs_scanned 10368     // 从启动到现在被扫描的切片数
kswapd_inodesteal 0     // 从启动到现在由kswapd回收用于其它目的的页面数
kswapd_low_wmark_hit_quickly 1
kswapd_high_wmark_hit_quickly 1
pageoutrun 8        // 从启动到现在通过kswapd调用来回收的页面数
pgrotated 3     // 从启动到现在请求直接回收的页面数
drop_pagecache 0
drop_slab 0
oom_kill 0
pgmigrate_success 2685
pgmigrate_fail 0
compact_migrate_scanned 0
compact_free_scanned 0
compact_isolated 16707
compact_stall 0
compact_fail 0
compact_success 0
compact_daemon_wake 0
compact_daemon_migrate_scanned 0
compact_daemon_free_scanned 0
htlb_buddy_alloc_success 0
htlb_buddy_alloc_fail 0
unevictable_pgs_culled 1464
unevictable_pgs_scanned 0
unevictable_pgs_rescued 5
unevictable_pgs_mlocked 932
unevictable_pgs_munlocked 2
unevictable_pgs_cleared 37
unevictable_pgs_stranded 33
swap_ra 0
swap_ra_hit 0

独特见解