蔚淦丞
发布于 2026-10-27 / 10 阅读
0
0

/proc/meminfo解读

⭐ 核心关注项(日常运维必看)

字段示例值含义运维要点
MemTotal3,649 MB物理内存总量服务器规格上限,不可变
MemFree717 MB完全空闲、未被任何进程或内核使用的内存⚠️ 此值低 ≠ 内存不足,Linux 会主动利用空闲内存做缓存
MemAvailable1,877 MB最关键指标。应用程序实际可用的内存估算值 = Free + 可回收的 Buffers/Cached/SReclaimable✅ 判断内存是否充足只看这个
Buffers210 MB块设备(磁盘)元数据缓存(目录项、inode 等)可被内核自动回收,属于"可用"内存的一部分
Cached908 MB文件内容页缓存。读取过的文件会缓存在这里,再次读取直接命中可被自动回收,属于"可用"内存的一部分
SwapTotal2,048 MBSwap 分区/文件总大小作为物理内存的溢出缓冲
SwapFree2,008 MB剩余可用 Swap⚠️ 若此值持续下降,说明物理内存压力大,正在频繁换页

💡 MemAvailable 计算公式

MemAvailable ≈ MemFree + Buffers + Cached + SReclaimable - 内核保留水位

为什么 MemFree 很低但系统正常?
Linux 的设计哲学是"空闲内存就是浪费的内存"。内核会将暂时不用的内存用于文件缓存(Cached/Buffers),加速系统运行。当应用需要内存时,这些缓存会被立即自动回收。因此 MemFree 低是正常的,只有 MemAvailable 低才代表真正的内存紧张。


活跃/非活跃页分类

内核根据页面的访问热度将其分为 Active 和 Inactive 两个 LRU 链表,回收内存时优先从 Inactive 链表开始。

字段示例值含义
Active696 MB最近频繁访问的页面总量
Inactive1,746 MB较久未访问的页面总量(优先被回收)
Active(anon)49 MB活跃页中的匿名页(进程堆栈、malloc 分配的内存)
Inactive(anon)1,293 MB非活跃匿名页,是 Swap 的主要候选对象
Active(file)647 MB活跃的文件缓存页
Inactive(file)452 MB非活跃文件缓存页,最容易被回收

🔍 诊断技巧

  • Inactive(anon) 很高 + SwapFree 下降 → 进程内存泄漏或内存不足,匿名页被迫换出
  • Active(file) 远高于 Inactive(file) → 文件 I/O 密集,大量文件被反复读取
  • Inactive(file) 占大头 → 正常的缓存行为,系统有大量可回收内存

内核内存与脏页

字段示例值含义运维要点
Dirty1.8 MB已修改但尚未写回磁盘的页缓存⚠️ 持续 > 数百 MB 说明磁盘 I/O 存在瓶颈
Writeback0 MB正在写回磁盘的页面非零表示内核正在刷盘
AnonPages1,315 MB所有匿名页总量(进程实际占用的物理内存)反映真实进程内存消耗
Mapped1,130 MB映射到进程地址空间的文件页(mmap)共享库、mmap 文件计入此项
Shmem18 MB共享内存(tmpfs、shmget、POSIX shm)Docker/tmpfs 使用量大时此值升高
Slab413 MB内核数据结构缓存总量= SReclaimable + SUnreclaim
SReclaimable347 MBSlab 中可回收部分(dentry/inode 缓存等)✅ 计入 MemAvailable
SUnreclaim65 MBSlab 中不可回收部分真正的内核固定开销
KernelStack5.6 MB内核线程栈占用线程数越多此值越高
PageTables23 MB页表占用内存进程越多 / 内存越大,此值越高

🔍 Slab 深入排查

当 Slab 异常偏高时,可通过以下命令定位具体是哪个内核缓存占用过多:

# 按大小排序查看各 slab 缓存
cat /proc/slabinfo | sort -k3 -rn | head -20

# 或使用 slub 调试(需开启 CONFIG_SLUB_DEBUG)
slabtop -o

🔍 基于 /proc/meminfo 的内存泄漏类型判断

核心思路:/proc/meminfo 本身不能直接"证明"泄漏,但通过字段间的差值计算 + 时序趋势对比,可以准确区分泄漏发生在用户态还是内核态,以及内核态中是 Slab 泄漏还是 Buddy(伙伴系统)泄漏。

一、用户态泄漏 vs 内核态泄漏的判断

关键公式

用户态实际占用 ≈ AnonPages + Mapped + Shmem
内核态实际占用 ≈ Slab + KernelStack + PageTables + VmallocUsed + Percpu
MemTotal = 用户态 + 内核态 + MemFree + Buffers + Cached

判断方法:观察 MemAvailable 下降时,哪个分量在增长

现象结论依据
MemAvailable 持续下降,AnonPages 同步单调递增用户态泄漏匿名页归进程所有,增长说明进程 malloc/mmap 未释放
MemAvailable 持续下降,Slab(尤其 SUnreclaim)同步单调递增内核态 Slab 泄漏Slab 是内核对象缓存,SUnreclaim 不可回收,增长即泄漏
MemAvailable 持续下降,AnonPages 和 Slab 均稳定,但 MemFree 持续减少且 Buffers/Cached 未增加内核态 Buddy 泄漏排除了用户态和 Slab 后,剩余内存消耗只能来自伙伴系统直接分配
MemAvailable 下降,但 Buffers/Cached 同步上升非泄漏正常的文件缓存增长,属于可回收内存

⚠️ 关键前提

  • 必须采集时序数据(至少 30 分钟、每 60s 采样),单次快照无法区分泄漏与正常波动
  • 判断前需先执行 echo 2 > /proc/sys/vm/drop_caches 排除缓存干扰,若 drop 后指标回落则非泄漏

二、内核态泄漏细分:Slab 泄漏 vs Buddy 泄漏

确认是内核态泄漏后,通过以下字段组合区分具体类型:

Slab 泄漏的特征

判据说明
SUnreclaim 单调递增Slab 中不可回收部分持续增长,是最直接的 Slab 泄漏信号
Slab - SReclaimable 差值扩大即使 SReclaimable 正常波动,只要总量减去可回收部分的净值在涨,就是 Slab 泄漏
VmallocUsed 稳定排除 vmalloc 区域的干扰
PageTables / KernelStack 稳定排除进程数增长带来的正常内核开销

补充验证:/proc/slabinfo 中某个缓存的 num_objs 只增不减,可与 meminfo 的 SUnreclaim 趋势交叉印证。

Buddy(伙伴系统)泄漏的特征

Buddy 分配器负责管理物理页帧的直接分配(非 Slab 对象),其泄漏在 meminfo 中的表现较为隐蔽:

判据说明
MemFree 持续下降,但 AnonPages / Slab / Buffers / Cached 均未增长内存被"吃掉"了,但不属于任何已知分类
DirectMap4k + DirectMap2M + DirectMap1G 之和持续增大DirectMap 反映内核直接映射的物理页总量,增长说明有物理页被内核直接持有未释放
VmallocUsed 可能同步增长部分 Buddy 分配通过 vmalloc 触发,两者可同时增长
SUnreclaim 稳定排除 Slab 泄漏

Buddy 泄漏的本质:内核代码通过 alloc_pages() / __get_free_pages() 直接申请物理页后未调用 free_pages() 释放。这类泄漏不经过 Slab 子系统,因此 SUnreclaim 不会体现,只能通过 "MemTotal 减去所有已知用途后的残差" 来发现。

残差计算公式(Buddy 泄漏量化)

Buddy_疑似泄漏量 = MemTotal - MemFree - Buffers - Cached 
                  - AnonPages - Mapped - Shmem 
                  - Slab - KernelStack - PageTables 
                  - VmallocUsed - Percpu - HugePages相关
  • 该残差在正常情况下应接近 0(通常 < 50MB)
  • 若残差随时间单调递增,即为 Buddy 泄漏的直接证据

三、决策流程图

MemAvailable 持续下降?
  ├─ 否 → 无泄漏
  └─ 是 → drop_caches 后是否恢复?
           ├─ 是 → 缓存行为,非泄漏
           └─ 否 → AnonPages 是否同步增长?
                    ├─ 是 → ✅ 用户态泄漏(查进程 RSS)
                    └─ 否 → SUnreclaim 是否同步增长?
                             ├─ 是 → ✅ 内核 Slab 泄漏(查 /proc/slabinfo)
                             └─ 否 → 计算残差是否持续增长?
                                      ├─ 是 → ✅ 内核 Buddy 泄漏(查 alloc_pages 调用点)
                                      └─ 否 → 检查 HardwareCorrupted / CmaUsed 等罕见字段
字段示例值含义运维要点
CommitLimit3,921 MB系统允许承诺分配的内存上限默认 = RAM × overcommit_ratio/100 + Swap
Committed_AS2,460 MB已承诺分配的内存总量⚠️ 接近 CommitLimit 时新进程可能 OOM
VmallocTotal34 TB内核虚拟内存区域总大小(64位系统)理论上限,无需关注
VmallocUsed17 MB已使用的 vmalloc 区域驱动/模块动态分配的内核内存
Percpu8.5 MBPer-CPU 变量占用CPU 核数越多此值越高

🔍 Overcommit 策略说明

# 查看当前 overcommit 策略
cat /proc/sys/vm/overcommit_memory
# 0 = 启发式(默认),1 = 始终允许,2 = 严格限制

# 查看 overcommit_ratio(仅策略2生效)
cat /proc/sys/vm/overcommit_ratio
  • 策略 0(默认):内核自行判断,大多数场景推荐
  • 策略 2:Committed_AS 不允许超过 CommitLimit,适合对 OOM 零容忍的关键业务

内存承诺与虚拟内存


大页内存(HugePages)

字段示例值含义
AnonHugePages655 MB透明大页(THP)占用的匿名内存
FileHugePages63 MB透明大页占用的文件缓存
HugePages_Total0静态大页总数(未启用)
HugePages_Free0可用静态大页数
Hugepagesize2048 kB大页尺寸(默认 2MB)
Hugetlb0 MB静态大页预留的总内存

💡 THP vs 静态大页

  • 透明大页(THP):内核自动管理,对应用透明。AnonHugePages 有值即表示 THP 在工作
  • 静态大页:需手动预留,适用于 DPDK、数据库等对内存延迟敏感的场景
  • 争议:THP 在某些数据库负载下可能导致性能抖动,生产环境建议根据业务测试结果决定是否关闭

硬件与底层映射

字段示例值含义运维要点
HardwareCorrupted0硬件检测到的内存损坏页数🚨 非零需立即排查硬件故障
DirectMap4k384 MB内核直接映射区中使用 4K 页的部分—
DirectMap2M3,643 MB内核直接映射区中使用 2M 页的部分占比越高,TLB 效率越好
DirectMap1G0 MB内核直接映射区中使用 1G 页的部分仅大内存服务器支持
CmaTotal / CmaFree0连续内存分配器总量/空闲嵌入式/驱动专用,一般服务器为 0

🔑 实战速查口诀

内存够不够       → 看 MemAvailable
有没有换页压力   → 看 SwapFree 变化趋势
磁盘 IO 卡不卡   → 看 Dirty + Writeback
内核吃多少       → 看 SUnreclaim + KernelStack + PageTables
会不会 OOM      → 看 Committed_AS vs CommitLimit
硬件坏没坏       → 看 HardwareCorrupted
缓存是否健康     → 看 Active/Inactive 比例

🛠️ 常用辅助命令

# 实时监控内存使用
free -h

# 查看各进程内存占用 TOP10
ps aux --sort=-%mem | head -11

# 查看 slab 缓存详情
slabtop -o

# 查看 NUMA 节点内存分布
numastat -m

# 查看内存压力事件(PSI)
cat /proc/pressure/memory

# 查看 zone 信息(内存碎片诊断)
cat /proc/zoneinfo

# 查看 buddy 分配器状态(高阶内存碎片)
cat /proc/buddyinfo

评论