一、概念
Linux 有两层内存分配:
1. 页级分配:伙伴系统,最小单位 4KB/2MB 内存页,粒度太大;
2. 对象级分配:内核经常要频繁创建/销毁小对象(task_struct、file、inode、socket、网络包、锁、队列节点等)。
如果每次都用 kmalloc 直接拆内存页分配、频繁申请/释放小块内存,会出现两大问题:
- 内存外部碎片、内部碎片严重;
- 频繁销毁新建对象,初始化/销毁开销极大,性能差。
于是诞生 SLAB 内存池机制,专门解决内核小对象高频分配问题。
SLAB:是 Linux 内核的对象缓存分配器,把连续的物理内存页,切分成固定大小的小对象,统一管理、复用。
SLUB 是 Linux 内核新一代 通用对象缓存分配器,用来替代传统 SLAB,是目前绝大多数 Linux 发行版默认的内核内存分配器。
作用和 SLAB 一致:管理内核小对象、缓存复用、减少内存碎片,只是架构做了极简重构
- SLAB:经典对象分配器(1996),结构复杂、队列多、锁粒度大、内存开销高,早期Linux默认。
- SLUB:2.6.22引入、2.6.23后默认;去队列、极简结构、每CPU无锁化、元数据开销极低、NUMA友好。
二、核心区别
1)设计哲学
- SLAB:功能完备、分层队列、复杂管理,追求通用与调试完备。
- SLUB:简单即美,删掉一切不必要抽象,可扩展性优先。
2)数据结构
- SLAB:独立 struct slab 描述符、三层队列(partial/full/free)、元数据独立,内存开销高。
- SLUB:无独立slab描述符,元数据(freelist/inuse)直接嵌入 struct page ;无队列、仅指针链表;每个CPU一个空闲链表。
3)锁与并发(SMP/NUMA)
- SLAB:全局锁+节点锁+CPU本地锁,锁争用严重、扩展性差。
- SLUB:per-CPU无锁化,分配/释放优先本地链表;仅本地空/满时才跨CPU/节点,锁粒度极小、SMP性能强、NUMA亲和。
4)内存开销
- SLAB:高(独立描述符、队列头、着色区)。
- SLUB:极低(元数据嵌page、无额外队列)。
5)调试
- SLAB:调试需重编译内核、全局开启,影响性能 。
- SLUB:内置调试、默认关闭;可按缓存单独开启,不影响全局性能 。
三、关键差异点
四、为什么SLUB替代SLAB
- 多核心/NUMA普及:SLAB锁争用严重,SLUBper-CPU无锁完美适配。
- 内存效率:SLUB元数据开销极低,大规模系统更省内存。
- 维护简单:代码精简、bug更少、调试更灵活 。
五、总结
SLAB是功能齐全但笨重的老架构;SLUB是去繁就简、面向多核与高并发的现代高性能分配器。