从零写OS(八):堆分配器,内核的 malloc

PMM 负责整页分配,每次给你 4KB。但内核里经常需要分配几十、几百字节的小块——存一个结构体、一条字符串。每次都要一整页,太浪费。 这一章实现 kmalloc / kfree:按需分配任意大小的内存块,用完归还,可以复用。 设计:空闲链表 最经典的堆实现:空闲链表(Free List)。 在堆空间里,每块内存前面加一个块头(header)记录元数据,所有块串成双向链表: typedef struct block { uint64_t size; // 这块数据区的大小(不含 header 本身) uint8_t is_free; // 1=空闲,0=已分配 struct block *next; // 链表后继 struct block *prev; // 链表前驱 } block_t; 内存布局长这样: [block_t header | ← size → 数据区 ][block_t header | ← size → 数据区 ] ... ↑ ↑ kmalloc 返回这个指针之前的地址 下一块 header kmalloc 返回的指针指向数据区起始,而不是 header。kfree 时把指针往前偏移 sizeof(block_t),找回 header,再改 is_free = 1。 堆在哪里 堆从虚拟地址 0x30000 开始,链表头指针存在 0x29000(一个固定位置,方便任何地方都能找到它): #define HEAP_START 0x30000ULL #define HEAP_HEAD_ADDR 0x29000ULL #define heap_head (*(block_t **)HEAP_HEAD_ADDR) 初始化时预先映射 4 页(16KB)作为起始堆空间,不够了再动态扩展。 ...

May 6, 2026 · 3 min · 大飞
京ICP备14031575号-3