📜  伙伴系统 – 内存分配技术(1)

📅  最后修改于: 2023-12-03 14:49:32.987000             🧑  作者: Mango

伙伴系统 – 内存分配技术

介绍

伙伴系统(Buddy System)是一种用于管理内存分配和回收的技术,它通过将内存划分为不同的大小类别,并以2的幂次方为单位来分配和回收内存。伙伴系统的原理是将内存按照大小分成不同的块,将大小相同、相邻的块放在一起,形成一棵完美的二叉树,树的根节点是整个可用内存的大小。伙伴系统支持快速分配和回收内存,在内存管理中应用广泛。

特点和优势
  1. 快速分配和回收内存:伙伴系统可以快速地分配和回收内存,因为它只需要在二叉树中搜索相应的内存块,而不需要扫描整个内存空间。这样可以大大减少分配和回收内存的时间。

  2. 内存碎片化低:伙伴系统可以将内存分配成大小相等的块,这样可以大大减少内存碎片化的问题。

  3. 可以提高内存使用效率:伙伴系统可以更好地利用可用内存,因为它可以按需分配和回收内存块,而不是一次性分配一大块内存,这样可以提高内存使用效率。

原理和实现

伙伴系统的原理是将可用的内存按照大小划分成不同的块,然后将相邻、大小相同的块放在一起,形成一棵完美的二叉树。每个节点表示一个内存块,节点的左儿子表示该节点的一半大小的内存块,右儿子表示同样大小的伙伴内存块。当一个内存块被分配出去时,它被标记为已使用,并将其伙伴块标记为已分配。当一个内存块被释放时,其伙伴块被检查,如果未被使用,则将两个伙伴块合并成一个更大的内存块,并递归进行合并,直到找到一个已分配的伙伴块或者到达根节点。

伙伴系统的实现需要考虑以下几个方面:

内存块的大小和对齐

为了保证内存块大小能够满足2的幂次方的要求,实现中通常会对内存块的大小进行对齐。例如,如果要分配一个大小为64字节的内存块,那么实际分配的内存大小可能会是128字节或256字节。

内存池的管理和维护

伙伴系统通常会在内存池上实现。内存池的大小是有限的,因此需要在内存分配和回收时进行管理和维护。例如,内存块的大小不能超过内存池的大小,并且需要避免内存池溢出。

算法的效率和复杂度

伙伴系统的效率和复杂度都比较高,但也存在一定的问题。例如,当内存块的大小过小时,可能会导致内存浪费和效率低下。此外,伙伴系统的实现也需要考虑空间的效率和可扩展性问题。

代码实现
#define PAGE_SHIFT 12
#define PAGE_SIZE (1UL << PAGE_SHIFT)
#define PAGE_MASK (~(PAGE_SIZE-1))
#define BUDDY_MAX_ORDER 11 /* 最大的块的大小 */
#define BUDDY_MIN_ORDER 4 /* 最小的块大小*/
#define BUDDY_START_ADDR 0x400000 /* 内存池的起始地址 */

/**
 * 定义伙伴结构
 */
 struct Buddy { 
    int next; /* 指向下一个块 */
    int prev; /* 指向上一个块 */
} buddy[1 << (BUDDY_MAX_ORDER)];

/**
 * 在二叉树中查找大小为 order 的伙伴块
 */
int buddy_find_order(int size)
{
    int order = BUDDY_MAX_ORDER - 1; 
    if (size > PAGE_SIZE)
        return -1;
    while (order) {
        if (size & (1UL << order))
            break;
        order--;
    }
    return order;
}

/**
 * 申请一个大小为 size 的伙伴块
 */
void *buddy_alloc(int size)
{
    int order;
    int curr;
    int buddy_idx;
    int i;
    void *ret;
    if (!size)
        return NULL;
    order = buddy_find_order(size);
    for (i = order; i < BUDDY_MAX_ORDER; i++) {
        if (!buddy[i].next)
            continue;
        curr = buddy[i].next;
        buddy_del(curr, i);
        buddy_idx = buddy_newindex(curr, i - 1);
        break;
    }
    if (i == BUDDY_MAX_ORDER) {
        return NULL;
    }
    ret = (void *)(((curr - BUDDY_START_ADDR) << PAGE_SHIFT));
    return ret;
}

/**
 * 释放一个伙伴块
 */
void buddy_free(void *ptr)
{
    int block;
    int order;
    int buddy_idx;
    block = ((unsigned long)ptr >> PAGE_SHIFT) + BUDDY_START_ADDR;
    order = BUDDY_MIN_ORDER;
    while (1) {
        buddy_idx = buddy_newindex(block, order);
        if (buddy[buddy_idx].next || block == 0)
            break;
        buddy_add(buddy_idx, order);
        block = block & ((1UL << order) - 1);
        order++;
    }
    buddy_add(buddy_idx, order);
}
参考资料
  1. Buddy memory allocation
  2. 内存管理算法之伙伴系统
  3. 操作系统课程-伙伴系统