本文档介绍了基于 Buddy 系统 的内存管理实现。Buddy 系统是一种经典的内存分配算法,通过将内存划分为 2 的幂次方大小的块,并根据需求进行分配和合并,来提高内存的使用效率并减少内存碎片。该系统在操作系统的内存管理中得到了广泛应用,尤其适用于动态内存分配。
内存对齐确保每个内存块的大小符合系统的对齐要求,在 Buddy 系统中,每个内存块的大小是 2 的幂次方,因此每次分配的内存块会自动对齐到页边界。通过对齐,能够避免内存碎片并提高内存访问的效率。
在分配内存时,内存地址会通过以下宏进行对齐:
p = (void*)PGROUNDDOWN((uint64)p);
PGROUNDDOWN
宏通过将地址向下取整来确保内存块的起始位置对齐到页的起始位置。
Buddy 系统通过合并相邻的空闲内存块(即“伙伴块”)来减少内存碎片。当内存块被释放时,系统会检查是否存在可以合并的相邻伙伴块,如果可以合并,则将它们合并成一个更大的块。
查找并合并伙伴块的示例代码如下:
while (order < MAX_ORDER) {
void *buddy_addr = find_buddy(p, order);
if (!buddy_addr) break;
struct run *curr = buddy.free_areas[order].free_list;
struct run *prev = 0;
int found_buddy = 0;
// 查找伙伴块
while (curr) {
if (curr == (struct run*)buddy_addr) {
// 合并伙伴块
if (curr->order != order) break;
if (prev) prev->next = curr->next;
else buddy.free_areas[order].free_list = curr->next;
buddy.free_areas[order].nr_free--;
p = (void*)((uint64)p & ~((1ULL << (order + 1)) * PGSIZE - 1));
order++;
block = (struct run*)p;
found_buddy = 1;
break;
}
prev = curr;
curr = curr->next;
}
if (!found_buddy) break;
}
为了保证并发操作的安全,特别是在多个线程或进程同时访问空闲内存链表时,系统使用了自旋锁。自旋锁确保在分配和释放内存时,空闲链表的操作是线程安全的。
获取和释放锁的示例:
acquire(&buddy.lock); // 获取锁
release(&buddy.lock); // 释放锁
内存切分与合并是确保内存分配高效且减少碎片的关键。系统在内存分配时会逐渐查找更大的空闲块,直到找到适合请求的内存块。当内存块释放时,系统会合并相邻的伙伴块,确保内存资源的最大化利用。
内存分配时的切分:
while (current_order <= MAX_ORDER) {
if (buddy.free_areas[current_order].free_list) {
block = buddy.free_areas[current_order].free_list;
buddy.free_areas[current_order].free_list = block->next;
buddy.free_areas[current_order].nr_free--;
break;
}
current_order++; // 尝试更大的 order
}