Linux命令-slabtop(实时显示内核 slab 缓存信息)
-
- [🔰 简介](#🔰 简介)
- [📖 语法](#📖 语法)
- [⚙️ 选项](#⚙️ 选项)
- [💡 实战示例](#💡 实战示例)
-
- [示例 1:基本 slabtop](#示例 1:基本 slabtop)
- [示例 2:按对象数排序](#示例 2:按对象数排序)
- [示例 3:一次性输出 + 监控](#示例 3:一次性输出 + 监控)
- [示例 4:诊断内核内存泄漏](#示例 4:诊断内核内存泄漏)
- [示例 5:常见 cache 名称识别](#示例 5:常见 cache 名称识别)
- [示例 6:与用户态内存工具对比](#示例 6:与用户态内存工具对比)
- [示例 7:性能调优场景](#示例 7:性能调优场景)
- [示例 8:自动化分析与脚本](#示例 8:自动化分析与脚本)
- [⚠️ 注意事项](#⚠️ 注意事项)
- [📝 总结](#📝 总结)
- [📚 相关命令](#📚 相关命令)
快速参考 slabtop 是 实时显示 Linux 内核 slab 分配器 缓存使用情况的工具,类似 top 但专门针对内核态内存(slab / slub / slob 三种分配器之一)。它显示各种内核对象的缓存命中率、对象数、占用内存 ,是诊断内核内存泄漏、内存碎片、驱动 bug 的核心工具。用户态 top 看进程内存,slabtop 看内核内存。
🔰 简介
| 项目 | 说明 |
|---|---|
| 命令全称 | slab top |
| 所属包 | procps-ng |
| 数据源 | /proc/slabinfo |
| 工作模式 | 实时刷新(默认 3 秒),或一次性输出 |
| 用途 | 诊断内核态内存问题 |
| 权限 | 需要 root(部分内核版本普通用户可见但不全) |
| 现代替代 | slabtop(命令本身) cat /proc/slabinfo(原始数据) perf / bpftool(高级诊断) |
slab / slub / slob 三种分配器:
| 分配器 | 特点 | 用途 |
|---|---|---|
slab |
原始实现,复杂 | 早期内核 |
slub |
简化版,Linux 默认 | 大多数发行版 |
slob |
极简版(Simple List of Blocks) | 嵌入式、小内存 |
slab 是什么:
- Linux 内核的小对象内存分配器 (替代频繁的
kmalloc/kfree) - 预先为常见对象(
task_struct、inode、dentry、buffer_head等)建立对象池(cache) - 申请对象时从 cache 取 ,避免反复创建/销毁
- 解决内存碎片问题
📖 语法
bash
slabtop [选项]
⚙️ 选项
| 选项 | 简写 | 说明 |
|---|---|---|
--delay=N |
-d N |
刷新间隔(秒),默认 3 |
--sort=SORT |
-s SORT |
排序字段(见下表) |
--once |
-o |
一次性输出(不刷新) |
--version |
-V |
版本 |
--help |
-? |
帮助 |
排序字段(-s 可选):
| 字段 | 含义 |
|---|---|
a |
ACTIVE 对象数 |
b |
对象数/页(OBJ/SLAB) |
c |
缓存大小(CACHE SIZE) |
l |
命中次数(HITS) |
n |
名称(NAME) |
o |
活跃对象数 × 对象大小(活跃内存) |
p |
每页对象数 / 每 slab |
s |
对象大小(OBJ SIZE) |
u |
缓存使用率 |
💡 实战示例
示例 1:基本 slabtop
bash
# 实时刷新(默认 3 秒)
$ sudo slabtop
Active / Total Objects (% used) : 678901 / 1234567 (55.0%)
Active / Total Slabs (% used) : 23456 / 34567 (67.9%)
Active / Total Caches (% used) : 98 / 142 (69.0%)
Total / Used Memory : 256789 / 145678
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
45678 34567 75% 0.50K 1234 37 49360K task_struct
12345 10987 89% 0.13K 412 30 16480K dentry
12345 10000 81% 0.06K 200 62 16000K kmalloc-64
9876 7890 80% 1.00K 2465 4 39440K inode
8765 7000 79% 0.25K 567 15 22680K kmalloc-256
...
字段详解:
| 字段 | 含义 |
|---|---|
OBJS |
该 cache 中总对象数 |
ACTIVE |
正在使用的对象数 |
USE |
使用率(ACTIVE/OBJS %) |
OBJ SIZE |
单对象大小 |
SLABS |
分配的 slab 页数 |
OBJ/SLAB |
每个 slab 含多少对象 |
CACHE SIZE |
该 cache 占用的总内存 |
NAME |
cache 名(task_struct 等) |
头部统计:
| 行 | 含义 |
|---|---|
Active / Total Objects |
活跃对象 / 总对象 |
Active / Total Slabs |
活跃 slab / 总 slab |
Active / Total Caches |
活跃 cache / 总 cache |
Total / Used Memory |
内存总量 / 使用量 |
示例 2:按对象数排序
bash
# 按 OBJS 排序(看哪个 cache 对象最多)
$ sudo slabtop -s a
# 按 CACHE SIZE 排序(看哪个 cache 占内存最多)
$ sudo slabtop -s c
# 按 NAME 排序
$ sudo slabtop -s n
# 按对象大小排序
$ sudo slabtop -s s
# 实战:找出最大 cache
$ sudo slabtop -s c -o | head -20
Active / Total Objects (% used) : 678901 / 1234567 (55.0%)
...
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1024000 800000 78% 0.50K 32768 32 4096000K dentry
500000 400000 80% 1.00K 12500 40 2000000K inode
200000 150000 75% 0.25K 2000 100 1600000K kmalloc-256
...
# 重点关注:CACHE SIZE 大的 = 占用内存多
示例 3:一次性输出 + 监控
bash
# 一次性输出(不刷新)
$ sudo slabtop -o
# 适合脚本处理
# 监控 5 秒输出
$ sudo slabtop -d 1 -o
# 每秒刷新一次
# 录制到文件做趋势分析
$ sudo slabtop -d 5 -o >> /var/log/slab.log &
# 持续 5 秒间隔输出
# 配合 grep
$ sudo slabtop -o | grep -E "dentry|inode|task_struct"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
45678 34567 75% 0.50K 1234 37 49360K task_struct
12345 10987 89% 0.13K 412 30 16480K dentry
9876 7890 80% 1.00K 2465 4 39440K inode
示例 4:诊断内核内存泄漏
bash
# 场景:系统内存持续增长,怀疑内核泄漏
# 1. 第一次记录
$ sudo slabtop -o > /tmp/slab_1.txt
$ date
2024-01-15 14:30:00
# 2. 等待 5 分钟
$ sleep 300
# 3. 第二次记录
$ sudo slabtop -o > /tmp/slab_2.txt
$ date
2024-01-15 14:35:00
# 4. 对比
$ diff /tmp/slab_1.txt /tmp/slab_2.txt
# 找出增长最快的 cache
# 例如:dentry 数量持续增长 = 文件系统相关驱动有问题
# 例如:nf_conntrack 持续增长 = 防火墙连接表泄漏
# 例如:vm_area_struct 持续增长 = 进程内存映射泄漏
# 5. 实战:自动化监控
$ cat /opt/scripts/slab_monitor.sh
#!/bin/bash
LOG=/var/log/slab_growth.log
THRESHOLD=10000 # 5 分钟增长阈值
prev_count=0
prev_name=""
while true; do
# 取 cache 中最大 5 个
output=$(slabtop -o | head -7 | tail -5)
# 提取最大 cache
max=$(echo "$output" | tail -1)
name=$(echo "$max" | awk '{print $NF}')
objs=$(echo "$max" | awk '{print $1}')
# 检测增长
if [ "$name" = "$prev_name" ] && [ $((objs - prev_count)) -gt $THRESHOLD ]; then
echo "[$(date)] 警告: $name 增长 $((objs - prev_count)) 个对象" >> $LOG
logger -p kern.warning "Slab cache $name growing: $objs"
fi
prev_name=$name
prev_count=$objs
sleep 300
done
示例 5:常见 cache 名称识别
bash
# ========== 1. 进程相关 ==========
$ sudo slabtop -o | grep -E "task_struct|signal|files_struct"
# task_struct: 进程描述符(每个进程 1 个)
# signal_struct: 信号结构
# files_struct: 进程打开的文件
# ========== 2. 文件系统相关 ==========
$ sudo slabtop -o | grep -E "dentry|inode|buffer_head"
# dentry: 目录项(**最常见大对象**)
# inode: 文件元数据
# buffer_head: 文件页缓存
# ========== 3. 网络相关 ==========
$ sudo slabtop -o | grep -E "sk_buff|sock|nf_conn"
# sk_buff: 网络数据包(**网络性能关键**)
# sock: 套接字
# nf_conn: netfilter 连接追踪
# ========== 4. 内存管理 ==========
$ sudo slabtop -o | grep -E "vm_area|page|mm_struct"
# vm_area_struct: 进程的虚拟内存区
# page: 内核页帧描述符
# ========== 5. 驱动相关 ==========
$ sudo slabtop -o | grep -E "scsi|usb|kvm"
# 各类驱动对象
# ========== 实战:dentry 增长 = 目录项泄漏 ==========
$ sudo slabtop -s c -o | head -10
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
1024000 800000 78% 0.13K 32768 32 4096K dentry
# 如果持续增长:
# 1. 检查是否有进程持续打开/关闭目录
# 2. 检查 NFS / FUSE 挂载
# 3. 同步检查 /proc/sys/fs/dentry-state
$ cat /proc/sys/fs/dentry-state
134567 109876 45 0 0 0
# nr_dentry / nr_unused / age_limit / ...
# 手动清理
$ echo 2 > /proc/sys/vm/drop_caches
# 释放 dentry + inode cache
示例 6:与用户态内存工具对比
bash
# ========== 1. 用户态 vs 内核态 ==========
# 用户态:top / ps
$ top
# 字段:VIRT(虚拟)/ RES(实际)/ SHR(共享)
# 这些是**进程**的用户态内存
# 内核态:slabtop
$ sudo slabtop
# 字段:OBJS / SLABS / CACHE SIZE
# 这些是**内核对象**的内存
# ========== 2. 完整内存视图 ==========
# 总览
$ free -h
total used free shared buff/cache available
Mem: 7.7G 1.2G 4.0G 100M 2.5G 6.0G
# total = 物理 RAM
# used = 已用(用户 + 内核 + 缓存)
# buff/cache = 内核页缓存(**会自动回收**)
# available = **真正可用**(含可回收缓存)
# 内核 slab 占多少?
$ sudo slabtop -o | head -1
Active / Total Objects (% used) : 678901 / 1234567 (55.0%)
Total / Used Memory : 256789 / 145678
# Used Memory = 内核 slab 占用的内存
# 用户态 + 内核态 = 完整内存占用
# ========== 3. /proc/meminfo 详细信息 ==========
$ grep -E "Slab|SReclaimable|SUnreclaim" /proc/meminfo
Slab: 145678 kB
SReclaimable: 87654 kB ← 可回收的 slab
SUnreclaim: 58024 kB ← 不可回收的 slab
# SReclaimable + SUnreclaim = Slab
# ========== 4. 完整内存全景图 ==========
$ cat /proc/meminfo | head -30
MemTotal: 8057892 kB
MemFree: 4123456 kB
MemAvailable: 6234567 kB
Buffers: 123456 kB
Cached: 2098765 kB
SwapCached: 0 kB
Active: 1234567 kB
Inactive: 1876543 kB
Active(anon): 456789 kB
Inactive(anon): 123456 kB
Active(file): 777778 kB
Inactive(file): 1753087 kB
Unevictable: 0 kB
Mlocked: 0 kB
SwapTotal: 2097148 kB
SwapFree: 2097148 kB
Dirty: 123 kB
Writeback: 0 kB
AnonPages: 580245 kB
Mapped: 234567 kB
Shmem: 123456 kB
KReclaimable: 87654 kB
Slab: 145678 kB
SReclaimable: 87654 kB
SUnreclaim: 58024 kB
KernelStack: 5678 kB
PageTables: 12345 kB
...
示例 7:性能调优场景
bash
# ========== 场景 1:网络服务器 sk_buff 增长 ==========
# 表现:网卡丢包、网络延迟
# 检查:
$ sudo slabtop -o | grep -E "sk_buff"
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
200000 180000 90% 0.25K 6250 32 200000K skbuff_head_cache
# 90% 使用率 = 接近上限,可能在网络高负载时丢包
# 解决:
# 1. 调整 netdev_max_backlog
$ sudo sysctl -w net.core.netdev_max_backlog=2000
# 2. 调整 socket 缓冲区
$ sudo sysctl -w net.core.rmem_max=12582912
$ sudo sysctl -w net.core.wmem_max=12582912
# ========== 场景 2:dentry 缓存不足 ==========
# 表现:磁盘 IO 高、stat() 慢
# 解决:调大 /proc/sys/vm/vfs_cache_pressure
$ cat /proc/sys/vm/vfs_cache_pressure
100
# 调小(保留更多 dentry)
$ sudo sysctl -w vm.vfs_cache_pressure=50
# ========== 场景 3:进程泄漏 task_struct ==========
# 表现:进程数持续增长
$ ps -e | wc -l
# 对应 slabtop 中 task_struct 增长
# 解决:定位并 kill 泄漏进程
$ ps aux --sort=-%mem | head -20
# 找出大内存进程
# ========== 场景 4:nf_conntrack 满 ==========
$ sudo slabtop -o | grep nf_conn
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
262144 262144 100% 0.31K 8192 32 1048576K nf_conntrack
# 100% 使用 = 防火墙连接表已满,新连接被拒绝
# 解决:
$ sudo sysctl net.netfilter.nf_conntrack_max=524288
$ sudo sysctl net.netfilter.nf_conntrack_tcp_timeout_established=600
# 调大连接上限 + 缩短超时
示例 8:自动化分析与脚本
bash
# ========== 1. slab 持续监控脚本 ==========
$ cat /opt/scripts/slab_watch.sh
#!/bin/bash
# 每 60 秒记录一次 slabtop 输出
LOG_DIR=/var/log/slab
mkdir -p $LOG_DIR
while true; do
TS=$(date +%F_%H%M%S)
slabtop -o > "$LOG_DIR/slab_$TS.txt"
# 清理 7 天前
find $LOG_DIR -name "slab_*.txt" -mtime +7 -delete
sleep 60
done
# ========== 2. 大 cache 告警 ==========
$ cat /opt/scripts/slab_alert.sh
#!/bin/bash
# 监控 cache > 1GB
THRESHOLD_KB=1048576 # 1GB
slabtop -o | tail -n +7 | awk -v thresh=$THRESHOLD_KB '
{
cache_kb = $7
gsub("K", "", cache_kb)
if (cache_kb > thresh) {
print "[ALERT] " $8 " cache 使用 " cache_kb "K 内存"
}
}' | while read line; do
logger -p kern.warning "Slab: $line"
echo "$line"
# 可加钉钉/邮件通知
done
# ========== 3. 与其他监控集成 ==========
$ cat /opt/scripts/slab_to_prometheus.sh
#!/bin/bash
# 转换 slabtop 为 prometheus 文本格式
OUT=/var/lib/node_exporter/textfile/slab.prom
echo "# HELP slab_cache_bytes Total bytes used by kernel slab cache" > $OUT
echo "# TYPE slab_cache_bytes gauge" >> $OUT
slabtop -o | tail -n +7 | awk '
{
cache_kb = $7
gsub("K", "", cache_kb)
gsub("M", "000", cache_kb)
cache_bytes = cache_kb * 1024
name = $8
gsub("-", "_", name)
print "slab_cache_bytes{name=\"" name "\"} " cache_bytes
}' >> $OUT
# prometheus node_exporter 采集
# 配合 grafana 画图
⚠️ 注意事项
1. 需要 root 权限
普通用户执行
slabtop会显示受限数据,仅当 kernel.yama.ptrace_scope=0 且/proc/slabinfo全员可读 。生产中必须 sudo。
2. /proc/slabinfo 内核选项部分内核配置
CONFIG_SLAB关闭时/proc/slabinfo不存在。检查:
bash$ cat /proc/slabinfo 2>/dev/null | head # 无输出 = 内核不导出内核 < 2.6.32 或嵌入式系统可能没。
3. SLAB vs SLUB vs SLOB 输出差异
- SLUB(现代默认):字段最全
- SLAB(老内核):字段少
- SLOB(嵌入式):几乎无数据
现代 Linux 都是 SLUB。
4. 高频率刷新影响
slabtop -d 1每秒刷新,会持续读取/proc/slabinfo。大量 cache(几万)时,读取可能 10-50ms 延迟 。
监控系统别用 < 5 秒间隔。
5. 排序字段大小写
slabtop -s a(活跃对象数)和-s A(某些版本)含义不同 。用
--sort=长格式更稳。
6. 名称中"-"的转义很多 cache 名含
-(kmalloc-64、nf_conn)。grep/awk 处理时用引号 或转义。
7. 与 /proc/meminfo 的关系
slabtop头部 "Used Memory" =/proc/meminfo中Slab字段。但只展示部分 (不是全部 cache)。
完整数据看
/proc/slabinfo原始文件。
8. 容器内的局限Docker 默认 PID 命名空间隔离,容器内
slabtop看到的是宿主机全局 。也可能因 cgroup 限制看到不同视图。
9. 数值单位
slabtop默认千字节 (K)。
OBJ SIZE是单对象大小(带K)。实际 K = 1024 字节,不是 1000。
10. 优化建议如果某个 cache 持续 100% 满且不能回收:
- 检查驱动 bug(升级内核)
- 调整
/proc/sys/vm/*参数- 重启服务/系统(最后手段)
- 启用
slab_nomerge(避免误合并)- 使用 BPF 工具做精细分析
📝 总结
slabtop 是"内核内存的 top"------专门看 slab 分配器。本节要点:
- 核心定位 :用户态内存用
top/ps,内核态内存用slabtop - 关键字段:OBJS/ACTIVE/USE/OBJ SIZE/SLABS/CACHE SIZE/NAME
- 诊断场景 :
- 内核内存增长 → 观察哪个 cache 在涨
- dentry 增长 → 目录项泄漏/缓存压力
- sk_buff 满 → 网络高负载
- nf_conntrack 满 → 防火墙拒绝连接
- 数据源 :
/proc/slabinfo(slabtop是美化器) - 配合使用 :
free(整体内存)/proc/meminfo(slab 详细)vmstat(slab 回收)ps(用户态进程内存)
最终建议 :日常巡检
slabtop -s c -o看最大 5 个 cache;内存告警 配合/proc/meminfo中 Slab 字段;深度诊断 用perf/bpftool抓具体内核对象;生产监控 导出 prometheus 指标。
📚 相关命令
| 命令 | 用途 |
|---|---|
slabtop |
实时 slab 信息(本节) |
top / htop |
用户态进程资源 |
free |
物理内存概览 |
cat /proc/slabinfo |
slab 原始数据 |
cat /proc/meminfo |
详细内存信息 |
vmstat |
虚拟内存统计 |
ps aux |
进程详情 |
pmap |
进程内存映射 |
sysctl |
调整内核参数 |
echo N > /proc/sys/vm/drop_caches |
手动回收缓存 |
perf |
性能分析 |
bpftool |
BPF 工具(高级) |
numastat |
NUMA 内存统计 |
sysstat / sar -r |
内存历史 |
crash |
内核转储分析(vmcore) |