Linux 内核内存管理:Slab 分配器原理与内存泄漏排查
Linux 内核内存管理:Slab 分配器原理与内存泄漏排查
一、Slab 分配器背景
Linux 内核需要频繁分配/释放小内存对象(如进程描述符、文件对象)。传统伙伴系统(Buddy System)以页(通常 4KB)为单位分配,会产生内部碎片。Slab 分配器通过对象缓存机制解决该问题,其核心思想是:
- 预分配内存块(slab)
- 将内存块划分为固定大小的对象
- 重复利用已释放对象
二、Slab 分配器原理
1. 三级结构
$$ \text{kmem_cache} \rightarrow \text{slab} \rightarrow \text{object} $$
- kmem_cache:核心控制结构,管理特定类型对象(如 task_struct)
- slab:物理内存页组成的容器
- object:实际分配的最小单元
2. 状态管理
每个 slab 有三种状态:
- 满状态:所有对象已分配
- 空状态:所有对象空闲
- 部分状态:部分对象分配中
状态转换通过双向链表实现,满足分配请求时优先使用部分状态 slab。
3. 分配算法
当请求分配对象时:
// 伪代码流程
if (部分状态 slab 存在)
从其获取空闲对象
else if (空状态 slab 存在)
升级为部分状态并分配
else
创建新 slab
4. 着色机制
为减少 CPU 缓存冲突,Slab 在对象间插入颜色偏移(color offset): $$ \text{实际地址} = \text{基地址} + \text{颜色值} \times \text{缓存行大小} $$ 通过分散对象起始位置,提升缓存利用率。
三、内存泄漏排查
当内核对象未正确释放时,会导致 slab 缓存持续增长,引发内存泄漏。
排查工具
-
/proc/slabinfo
查看所有 slab 缓存状态:awk '{print $1,$2,$3,$4}' /proc/slabinfo | sort -k2 -nr关注
active_objs(活跃对象)与num_objs(总对象)比值异常缓存。 -
kmemleak
内核内置检测工具,启用后扫描未引用内存:echo scan > /sys/kernel/debug/kmemleak # 触发扫描 cat /sys/kernel/debug/kmemleak # 查看泄漏点 -
slabtop
实时监控 slab 使用:slabtop -s c # 按缓存大小排序持续观察
ACTIVE列增长情况。
排查步骤
-
定位异常缓存
通过/proc/slabinfo找到对象数量持续增长的缓存名(如dentry)。 -
分析分配路径
使用ftrace跟踪对象分配:echo 1 > /sys/kernel/debug/tracing/events/kmem/kmalloc/enable cat /sys/kernel/debug/tracing/trace_pipe -
检查引用链
对于已知泄漏对象,通过crash工具分析引用关系:crash -s vmlinux vmcore > kmem -s kmem_cache_name
四、优化建议
- 定期监控
/proc/meminfo中的Slab字段 - 为高频小对象设置专用缓存(
kmem_cache_create()) - 在驱动模块卸载时强制回收缓存(
kmem_cache_destroy())
通过理解 Slab 的对象复用机制和状态管理策略,结合内核提供的诊断工具,可有效定位内存泄漏根源。实际应用中需注意:频繁创建/销毁缓存本身也会消耗资源,应保持缓存生命周期与业务需求匹配。
更多推荐

所有评论(0)