前言

内存管理是 Linux 内核最复杂也是最重要的子系统之一。理解内核内存管理机制,不仅能写出更高性能的程序,也能在系统调优、故障排查时游刃有余。本文以实战视角,从物理内存分配到用户态内存接口,深入剖析 Linux 内核内存管理的完整架构。

一、物理内存管理:Buddy System 与 Slab 分配器

1.1 伙伴系统(Buddy Allocator)

Linux 内核使用 Buddy System 管理物理页框(Page Frame)。核心思想是将空闲页面按 2 的幂次分组(order-0 到 order-10,即 4KB 到 4MB),分配时按需分裂,释放时自动合并。

// 分配 2^order 个连续物理页
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order);

// 释放
void __free_pages(struct page *page, unsigned int order);

伙伴系统的优势在于减少外部碎片——相邻同阶空闲块会自动合并为更大阶的块。但无法解决内部碎片问题:申请 5KB 会拿到 8KB 的 order-1 块,浪费 3KB。这正是 Slab 分配器要解决的。

1.2 内核页面分配的核心数据结构

每个 NUMA 节点维护一个 struct zone 数组,按区域类型(DMA/Normal/HighMem)组织。每个 zone 内维护一个 free_area 数组,按 order 索引:

struct zone {
    struct free_area    free_area[MAX_ORDER]; // 伙伴系统空闲链表
    ...
};

struct free_area {
    struct list_head    free_list[MIGRATE_TYPES];
    unsigned long       nr_free;
};

迁移类型(MIGRATE_TYPES)是 Linux 对抗外部碎片的重要机制——将不可移动页(kmem_cache 分配)、可回收页(page cache)、可移动页(用户态匿名页)分类存放,减少碎片化。

1.3 Slab 分配器家族

Slab 是建立在伙伴系统之上的对象缓存层,专门用于高频小对象分配:

  • Slab:传统实现,hwcache-aligned 的单 CPU 缓存(已逐步淡出)
  • Slub:现代默认分配器,简化元数据,CPU partial 链减少碎片
  • Slob:嵌入式场景极简方案,O(n) 分配
// 创建专用 cache
struct kmem_cache *kmem_cache_create(const char *name, size_t size,
                                      unsigned long flags, void (*ctor)(void *));

// 从 cache 分配/释放对象
void *kmem_cache_alloc(struct kmem_cache *cache, gfp_t flags);
void kmem_cache_free(struct kmem_cache *cache, void *obj);

// 通用小对象分配(按大小自动路由到对应 kmem_cache)
void *kmalloc(size_t size, gfp_t flags);
void kfree(const void *obj);

1.4 Slub 实战调优

Slub 分配器的 /proc/slabinfo 包含关键的缓存元数据:

$ sudo cat /proc/slabinfo | head -20
slabinfo - version: 2.1
# name        
dentry      284010  284148    192   21    1
inode_cache 253427  253440    624   25    2
vm_area_struct 42050  42201    176   22    1
mm_struct     2048   2048    736   11    2
task_struct   2048   2048   5824    2   32

当看到 num_objs 远大于 active_objs 时,说明缓存中有大量空闲 slab 页,可以通过 /sys/kernel/slab/

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论
立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部