Linux性能统计 - cat /proc/meminfo

本文介绍了通过cat /proc/meminfo命令查看Linux系统内存信息,分别解释了32位和64位系统下的各项内存指标,如LowTotal、LowFree、SwapTotal、CommitLimit等,以及它们在系统内存管理中的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

32位系统


$cat /proc/meminfo

MemTotal: 2052440 kB //Total amount of physical RAM, in kilobytes.
MemFree: 50004 kB //The amount of physical RAM, in kilobytes, left unused by the system.
Buffers: 19976 kB //The amount of physical RAM, in kilobytes, used for file buffers.
Cached: 436412 kB //The amount of physical RAM, in kilobytes, used as cache memory.
SwapCached: 19864 kB //The amount of swap, in kilobytes, used as cache memory.
Active: 1144512 kB //The total amount of buffer or page cache memory, in kilobytes, that is in active use. This is memory that has been recently used and is usually not reclaimed for other purposes.
Inactive: 732788 kB //The total amount of buffer or page cache memory, in kilobytes, that are free and available. This is memory that has not been recently used and can be reclaimed for other purposes.
Active(anon): 987640 kB
Inactive(anon): 572512 kB
Active(file): 156872 kB //Active(file), Inactive(file) has file back-end which means its original file is in disk but to use it faster it was loaded on RAM.
Inactive(file): 160276 kB
Unevictable: 8 kB
Mlocked: 8 kB
HighTotal: 1177160 kB //The total and free amount of memory, in kilobytes, that is not directly mapped into kernel space. The HighTotal value can vary based on the type of kernel used.
HighFree: 7396 kB
LowTotal: 875280 kB //The total and free amount of memory, in kilobytes, that is directly mapped into kernel space. The LowTotal value can vary based on the type of kernel used.
<think>我们分析`/proc/meminfo`的实现原理,需要从内核源码入手。该文件属于proc文件系统,其内容由内核动态生成。主要涉及以下源码文件(以Linux 5.x内核为例): 1. `fs/proc/meminfo.c`:该文件定义了`/proc/meminfo`的显示内容。 2. `include/linux/mmzone.h`:包含内存区域(zone)的相关定义。 3. `mm/page_alloc.c`:包含页面分配器的统计信息。 4. `mm/vmstat.c`:包含虚拟内存统计信息。 ### 1. `/proc/meminfo`的注册 在`fs/proc/meminfo.c`中,通过`proc_create`或`proc_create_single`创建`/proc/meminfo`文件节点。在较新的内核版本中,使用`proc_create_single`: ```c static int __init proc_meminfo_init(void) { proc_create_single("meminfo", 0, NULL, meminfo_proc_show); return 0; } fs_initcall(proc_meminfo_init); ``` ### 2. 显示函数`meminfo_proc_show` 该函数负责生成`/proc/meminfo`的内容。其核心是调用`show_val_kb`或`seq_printf`等函数输出每一行信息。主要步骤包括: 1. 获取系统内存统计信息(如`si_meminfo`)。 2. 获取各个内存区域的统计信息(通过`for_each_online_pgdat`和`for_each_zone`遍历)。 3. 计算各种内存使用量(如活跃内存、非活跃内存等)。 ### 3. 关键数据结构 - `struct sysinfo`:定义在`include/linux/sysinfo.h`中,包含系统内存的总体信息。 ```c struct sysinfo { long totalram; // 总内存(以页为单位) long freeram; // 空闲内存 long sharedram; // 共享内存 long bufferram; // 缓冲内存 ... // 其他字段 }; ``` - `struct zone`:定义在`include/linux/mmzone.h`中,表示内存区域(如DMA、Normal、HighMem等)的状态。 ### 4. 主要字段实现原理 #### (1) `MemTotal` 系统总内存,从`struct sysinfo`的`totalram`字段获得,乘以页面大小(通常4KB): ```c si_meminfo(&i); // 填充sysinfo结构 show_val_kb(m, "MemTotal: ", i.totalram); ``` 其中`show_val_kb`将页面数转换为KB: ```c static void show_val_kb(struct seq_file *m, const char *s, unsigned long num) { seq_printf(m, "%s%lu kB\n", s, num << (PAGE_SHIFT - 10)); } ``` 这里`PAGE_SHIFT`通常是12(因为$2^{12}=4096$),所以左移2位(即乘以4)转换为KB。 #### (2) `MemFree` 空闲内存,来自`sysinfo`的`freeram`: ```c show_val_kb(m, "MemFree: ", i.freeram); ``` #### (3) `Buffers`和`Cached` - `Buffers`:块设备使用的缓冲区(如文件系统元数据),来自`sysinfo`的`bufferram`。 - `Cached`:文件页缓存(从文件读取的内容),通过全局变量`global_node_page_state(NR_FILE_PAGES)`减去`Buffers`和`SwapCached`得到。 ```c cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; ``` #### (4) `Slab` 内核对象缓存(通过`kmem_cache`分配的内存),来自`global_node_page_state(NR_SLAB_RECLAIMABLE)`和`global_node_page_state(NR_SLAB_UNRECLAIMABLE)`之和。 #### (5) `KernelStack` 内核栈使用量,来自`global_node_page_state(NR_KERNEL_STACK_KB)`。每个用户线程分配的内核栈大小固定(如8KB或16KB),统计时转换为KB。 #### (6) `MemAvailable` 估算可用内存(无需交换即可分配的内存),通过`si_mem_available()`函数计算: ```c show_val_kb(m, "MemAvailable: ", available); ``` 该函数在`mm/page_alloc.c`中定义,核心逻辑: ```c available = global_zone_page_state(NR_FREE_PAGES) - totalreserve_pages; available += global_node_page_state(NR_INACTIVE_FILE) + global_node_page_state(NR_ACTIVE_FILE); available += global_node_page_state(NR_SLAB_RECLAIMABLE); available -= min(available * 20 / 100, totalreserve_pages); // 保留一部分 ``` ### 5. 内存统计的更新机制 内核在分配/释放页面时,通过`zone_page_state_add`等函数更新内存统计计数(位于`mm/vmstat.c`)。例如: - 分配页面:`__mod_zone_page_state(zone, NR_FREE_PAGES, - (1 << order))` - 释放页面:`__mod_zone_page_state(zone, NR_FREE_PAGES, 1 << order)` ### 6. 示例代码片段 以下是`meminfo_proc_show`函数的部分代码(简化): ```c static int meminfo_proc_show(struct seq_file *m, void *v) { struct sysinfo i; unsigned long committed; long cached; long available; ... // 其他局部变量 si_meminfo(&i); // 获取sysinfo show_val_kb(m, "MemTotal: ", i.totalram); show_val_kb(m, "MemFree: ", i.freeram); show_val_kb(m, "MemAvailable: ", available); show_val_kb(m, "Buffers: ", i.bufferram); ... // 其他字段 // 计算Cached cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; show_val_kb(m, "Cached: ", cached); // 计算Slab slab = global_node_page_state(NR_SLAB_RECLAIMABLE) + global_node_page_state(NR_SLAB_UNRECLAIMABLE); show_val_kb(m, "Slab: ", slab); ... // 其他字段(如SwapTotal, SwapFree等) return 0; } ``` ### 总结 `/proc/meminfo`通过动态遍历内核内存统计信息生成内容,其数据来源包括: 1. `struct sysinfo`:系统级内存统计。 2. 全局内存统计(`global_node_page_state`等):按节点和区域统计的页面计数。 3. 特定内存管理子系统的统计(如Slab、Swap等)。 这些统计值在内核内存管理代码中动态更新,确保`/proc/meminfo`实时反映系统内存状态。 ### 相关问题 1. 如何在内核模块中读取`/proc/meminfo`的信息? 2. 内核内存统计计数(如`NR_FREE_PAGES`)是如何更新的? 3. `MemAvailable`的估算算法是否准确?在什么情况下会不准确? 4. 为什么`Buffers`和`Cached`要分开统计?</think>### `/proc/meminfo`实现原理与内核源码分析 `/proc/meminfo`的实现基于Linux内核的proc文件系统机制,其核心是通过动态生成文件内容来展示系统内存状态。以下是关键实现原理分析: #### 1. **proc文件系统注册** 在`fs/proc/meminfo.c`中注册文件节点: ```c static int __init proc_meminfo_init(void) { proc_create_single("meminfo", 0, NULL, meminfo_proc_show); return 0; } fs_initcall(proc_meminfo_init); ``` 当用户执行`cat /proc/meminfo`时,内核调用`meminfo_proc_show()`生成内容[^1]。 #### 2. **核心函数`meminfo_proc_show()`** 该函数收集并格式化内存数据(Linux 5.15内核简化版): ```c static int meminfo_proc_show(struct seq_file *m, void *v) { struct sysinfo i; unsigned long pages[NR_LRU_LISTS]; ... si_meminfo(&i); // 获取基础内存信息 show_val_kb(m, "MemTotal: ", i.totalram); show_val_kb(m, "MemFree: ", i.freeram); // 计算Cached值 cached = global_node_page_state(NR_FILE_PAGES) - total_swapcache_pages() - i.bufferram; show_val_kb(m, "Cached: ", cached); // 计算Slab内存 slab_reclaimable = global_node_page_state(NR_SLAB_RECLAIMABLE); slab_unreclaimable = global_node_page_state(NR_SLAB_UNRECLAIMABLE); show_val_kb(m, "Slab: ", slab_reclaimable + slab_unreclaimable); // 计算内核栈 (KernelStack) stack_pages = global_node_page_state(NR_KERNEL_STACK_KB); seq_printf(m, "KernelStack: %8lu kB\n", stack_pages); // 计算可用内存 (MemAvailable) available = si_mem_available(); show_val_kb(m, "MemAvailable: ", available); ... } ``` #### 3. **关键数据结构** - **`struct sysinfo`**(`include/linux/sysinfo.h`): ```c struct sysinfo { long totalram; // 总物理内存 long freeram; // 空闲内存 long bufferram; // 缓冲区内存 ... }; ``` - **内存区域统计**(`mmzone.h`): ```c enum zone_stat_item { NR_FREE_PAGES, // 空闲页 NR_FILE_PAGES, // 文件缓存页 NR_SLAB_RECLAIMABLE, // 可回收Slab ... }; ``` #### 4. **关键指标计算原理** 1. **MemTotal** $$ \text{MemTotal} = \text{totalram} \times \text{PAGE\_SIZE}/1024 $$ 来自`si_meminfo()->totalram`,包含所有物理内存[^1]。 2. **MemAvailable** 估算公式(`mm/page_alloc.c`): ```c available = global_zone_page_state(NR_FREE_PAGES) + global_node_page_state(NR_INACTIVE_FILE) + global_node_page_state(NR_ACTIVE_FILE) + global_node_page_state(NR_SLAB_RECLAIMABLE) - min(watermark[WMARK_LOW], totalreserve_pages); ``` 反映无需交换即可分配的内存[^3]。 3. **KernelStack** 每个线程内核栈大小固定(64位系统16KB),统计值: $$ \text{KernelStack} = \text{NR\_THREADS} \times 16\text{KB} $$ 通过`global_node_page_state(NR_KERNEL_STACK_KB)`获取[^2]。 4. **Slab** 包含可回收(`NR_SLAB_RECLAIMABLE`)和不可回收(`NR_SLAB_UNRECLAIMABLE`)两部分,由`kmem_cache`分配器管理。 #### 5. **数据更新机制** 内存统计值通过原子操作实时更新: ```c // 当分配页面时(mm/page_alloc.c) __mod_zone_page_state(zone, NR_FREE_PAGES, -(1 << order)); ``` - **页面分配器**:更新`NR_FREE_PAGES` - **VFS层**:文件读写时更新`NR_FILE_PAGES` - **Slab分配器**:更新`NR_SLAB_*`计数 #### 6. **proc文件系统特性** - **动态生成**:每次读取时实时计算 - **零拷贝输出**:通过`seq_file`接口直接写入内核缓冲区 - **无持久存储**:数据仅存在于内存中 ### 总结流程图 ```mermaid graph TD A[cat /proc/meminfo] --> B[VFS层调用procfs] B --> C[调用meminfo_proc_show] C --> D1[获取sysinfo结构体] C --> D2[查询全局内存统计] C --> D3[计算复合指标] D1 --> E[输出MemTotal/MemFree] D2 --> E[输出Slab/KernelStack] D3 --> E[输出MemAvailable] E --> F[格式化字符串到用户空间] ``` ### 相关问题 1. 为什么`MemAvailable`不等于`MemFree + Buffers + Cached`?[^3] 2. 内核如何确保内存统计计数的原子性和准确性? 3. 为什么`KernelStack`统计值不包含在进程的RSS中?[^2] 4. 在内存压力下,`/proc/meminfo`的哪些指标会首先发生变化? 5. 如何通过内核模块扩展`/proc/meminfo`的输出内容? [^1]: `/proc/meminfo` 是一个特殊的文件,它存在于 Linux 操作系统中,用于提供关于系统内存使用情况的信息。 [^2]: Kernel stack(内核栈)是常驻内存的,既不包括在LRU lists里,也不包括在进程的RSS/PSS内存里。 [^3]: MemAvailable≈MemFree+Buffers+Cached,它是内核使用特定的算法估算出来的,并不精确。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值