Linux内核分析之内存管理-08
Linux 6.12 内存管理详解 - 第8章:Slab 分配器与 PCP
基于 Linux 6.12.38 源码
8.1 概述:内存分配层次结构
Linux 内核的内存管理采用分层架构,从底层到上层依次为:
1 | ┌─────────────────────────────────────────────────────────────────┐ |
为什么需要多层分配器?
| 层次 | 问题 | 解决方案 |
|---|---|---|
| 伙伴系统 | 最小分配单位 4KB,小对象浪费严重 | - |
| PCP | 频繁获取 zone->lock,竞争激烈 | Per-CPU 缓存减少锁竞争 |
| Slab | 对象构造/析构开销,内存碎片 | 对象池,减少碎片,缓存热点对象 |
8.2 PCP (Per-CPU Pageframe Allocator)
8.2.1 PCP 设计目的
问题:
在 PCP 引入之前,每次分配和释放页面都需要获取 zone->lock,这在多处理器系统上导致严重的锁竞争。
解决方案:
为每个 CPU 的每个 zone 维护独立的页面缓存,大多数分配/释放可以在无锁或少锁的情况下完成。
位置: mm/page_alloc.c, include/linux/mmzone.h
8.2.2 PCP 数据结构
1 | /* 位置: include/linux/mmzone.h:683 */ |
PCP 列表数量:
1 | /* 位置: include/linux/mmzone.h:665 */ |
zone 中的 PCP:
1 | /* 位置: include/linux/mmzone.h:843 */ |
8.2.3 PCP 工作原理
水位管理:
1 | high |
batch 动态调整:
1 | /* 位置: mm/page_alloc.c:2973 */ |
8.2.4 PCP 分配流程
完整分配路径:
1 | __alloc_pages() |
关键代码分析:
1 | /* 位置: mm/page_alloc.c:3021 */ |
8.2.5 PCP 释放流程
完整释放路径:
1 | __free_pages() / put_page() |
释放提交代码:
1 | /* 位置: mm/page_alloc.c:2624 */ |
8.2.6 PCP 批量释放到伙伴系统
1 | /* 位置: mm/page_alloc.c:1171 */ |
8.2.7 PCP 水位衰减
1 | /* 位置: mm/page_alloc.c:2366 */ |
8.2.8 PCP 支持的分配阶数
1 | /* 位置: mm/page_alloc.c:542 */ |
8.3 SLUB 分配器 (默认实现)
8.3.1 SLUB 概述
设计目标:
- 简化数据结构
- 减少 Cache Line 占用
- 提高分配性能
- 更好的 NUMA 支持
位置: mm/slub.c
SLUB 特点:
| 特性 | SLAB | SLUB |
|---|---|---|
| Per-CPU 队列 | 3个列表 (full, partial, free) | 单个 freelist |
| 对象指针 | 间接引用 | 直接引用 |
| 内存开销 | 较高 | 较低 |
| 代码复杂度 | 高 | 低 |
| 调试功能 | 有限 | 丰富 |
8.3.2 SLUB 数据结构
kmem_cache 结构:
1 | /* 位置: include/linux/slub_def.h */ |
Per-CPU 数据:
1 | /* 位置: mm/slub.c:384 */ |
节点数据:
1 | /* 位置: mm/slub.c:425 */ |
8.3.3 SLUB Slab 状态
Slab 四种状态:
1 | ┌─────────────────────────────────────────────────────────────────┐ |
8.3.4 SLUB 分配流程
完整分配路径:
1 | kmem_cache_alloc(s, flags) |
快速路径代码:
1 | /* 位置: mm/slub.c:3934 */ |
TID (Transaction ID) 机制:
1 | TID 机制确保无锁路径的正确性: |
8.3.5 SLUB 释放流程
完整释放路径:
1 | kmem_cache_free(s, object) |
8.3.6 SLUB slab 分配
从伙伴系统分配 slab:
1 | /* 位置: mm/slub.c */ |
8.3.7 SLUB 对象布局
1 | ┌────────────────────────────────────────────────────────────────┐ |
8.4 SLAB 分配器 (传统实现)
8.4.1 SLAB 概述
特点:
- 原始的 slab 分配器实现
- 三队列管理 (full, partial, free)
- 更复杂但功能完整
- 支持着色 (coloring) 优化缓存行使用
注意: 在 Linux 6.12 中,SLAB 已被标记为过时,SLUB 是默认且推荐的实现。
8.4.2 SLAB 数据结构
1 | /* 位置: include/linux/slab_def.h */ |
8.4.3 SLAB 三队列管理
1 | ┌─────────────────────────────────────────────────────────────────┐ |
8.5 SLOB 分配器 (已移除)
8.5.1 SLOB 概述
注意: SLOB 已在较新的内核版本中被移除。
历史特点:
- 极简的 slab 实现
- 适合资源受限的嵌入式系统
- 使用简单的链表管理空闲块
- 内存开销最小,但性能较低
移除原因:
- SLUB 已经足够高效
- 维护三种实现的成本高
- SLUB tiny 配置可以满足大多数嵌入式需求
8.6 kmalloc 实现
8.6.1 kmalloc 缓存数组
kmalloc 大小类别:
1 | /* 位置: mm/slab_common.c */ |
8.6.2 kmalloc 实现
1 | /* 位置: mm/slub.c:4263 */ |
8.6.3 kmalloc 大小选择
1 | size <= 192: 使用 2 的幂次对齐 |
8.7 调试与监控
8.7.1 Slab 调试选项
1 | # SLUB 调试 |
8.7.2 调试接口
1 | # 查看 slab 信息 |
8.7.3 调试示例
查找内存泄漏:
1 | # 1. 记录初始状态 |
跟踪分配:
1 | # 启用跟踪 |
8.7.4 SLUB 统计
1 | /* 位置: mm/slub.c */ |
8.8 性能优化
8.8.1 Per-CPU 优化
1 | /* 定义 Per-CPU 变量 */ |
8.8.2 批量操作
1 | /* 批量分配 */ |
8.8.3 NUMA 优化
1 | /* 从本地节点分配 */ |
8.8.4 对象构造
1 | /* 使用构造函数初始化对象 */ |
8.9 常见问题
8.9.1 Slab 泄漏
症状:
- 系统内存持续增长
- /proc/meminfo 中 Slab 持续增加
- 系统性能下降
诊断:
1 | # 查看哪个缓存增长最快 |
8.9.2 Slab 碎片
症状:
- 大量 partial slabs
- 内存利用率低
解决:
1 | # 合并相同的缓存 |
8.9.3 性能问题
症状:
- 分配/释放慢
- 高 CPU 使用率
解决:
- 检查是否使用了正确的分配器
- 考虑使用批量分配
- 优化对象大小
- 检查是否有缓存抖动
8.10 本章小结
本章详细介绍了 Linux 6.12 的内存分配器系统:
8.10.1 PCP (Per-CPU Pageframe Allocator)
- 设计目的: 减少 zone->lock 竞争
- 关键结构:
struct per_cpu_pages - 工作原理: Per-CPU 页面缓存,批量操作
- 支持阶数: 0 到 PAGE_ALLOC_COSTLY_ORDER (3)
8.10.2 SLUB 分配器 (默认)
- 设计目标: 简化结构,提高性能
- 关键结构:
struct kmem_cache_cpu,struct kmem_cache_node - Slab 状态: CPU Slab, CPU Partial, Node Partial, Full
- 无锁分配: 基于 TID 的 lockless fastpath
8.10.3 SLAB 分配器 (传统)
- 特点: 三队列管理,功能完整
- 状态: 已标记为过时
- 适用: 特定场景或兼容性需求
8.10.4 SLOB 分配器
- 状态: 已在较新版本中移除
- 原因: SLUB 已足够高效
8.10.5 分配层次
1 | 用户接口 (kmalloc/kmem_cache_alloc) |
8.10.6 关键函数位置
| 函数 | 位置 |
|---|---|
__rmqueue_pcplist |
mm/page_alloc.c:3021 |
rmqueue_pcplist |
mm/page_alloc.c:3052 |
free_unref_page |
mm/page_alloc.c:2675 |
free_pcppages_bulk |
mm/page_alloc.c:1171 |
slab_alloc_node |
mm/slub.c:4127 |
__slab_alloc_node |
mm/slub.c:3934 |
kmem_cache_alloc |
mm/slub.c:4158 |
下一章将介绍缺页异常处理。
- Title: Linux内核分析之内存管理-08
- Author: 韩乔落
- Created at : 2026-01-20 21:39:23
- Updated at : 2026-02-24 14:05:31
- Link: https://jelasin.github.io/2026/01/20/Linux内核分析之内存管理-08/
- License: This work is licensed under CC BY-NC-SA 4.0.
Comments