堆管理算法中的Buddy System(伙伴系统)算法

在一个Buddy System算法中,堆管理者只分配特定大小的内存块,成为permitted size。针对每个permitted size,都有一个空闲链表来维护。

一般这些大小会选择2的幂次方,或者斐波那契数列。因为这样会方便地将除最小的那个数之外的其它数都分为两个permitted size之和。

当负责分配内存的堆管理者接受到请求s大小的内存请求时,会讲s对齐到一个permitted size。然后从那个permitted size的空闲链表中分配一块内存给他。如果没有在那个空闲链表中找到内存,就在大一级的内存中找一块内存分配给用户,然后将剩余的另一半挂到这个permitted size的空闲链表中。

这个算法中的空闲链表一般采用位图(bitmap)算法来实现。因为这样会使内存回收合并变得很高效。

在Zend引擎中的堆管理算法中就使用到了伙伴系统算法,我们来看一下zend_mm_heap结构中相关的数据结构:

zend_mm_free_block *free_buckets[ZEND_MM_NUM_BUCKETS*2];

这个 free_buckets 就是一个空闲链表的二位数组。ZEND_MM_NUM_BUCKETS 定义了分配时最大的幂值。每一个幂值都对应一个 *free_buckets,就是一个空闲链表。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
伙伴系统Buddy System)是一种动态内存分配算法,它的主要思想是将内存空间划分为一些大小相等的块,每个块的大小为2的幂次方,且每个块的大小是相邻两个块大小的二分之一。这样,内存的所有块大小都是2的幂次方,且相邻块大小之间的比例为1:2。 伙伴系统分配内存时,首先按照内存大小找到对应的块。如果找到的块正好可以分配给用户,那么就直接将该块分配给用户;如果找到的块比用户所需的块大,那么就将该块分成两个大小相等的块,其一个块分配给用户,另一个块留作备用。如果备用块大小正好与用户所需的块大小相等,那么就直接将备用块分配给用户;否则就将备用块继续分成两个大小相等的块,其一个块分配给用户,另一个块留作备用。这样,直到找到一个大小正好能够分配给用户的块或者无法再次分割备用块为止。 以下是基于C语言实现的伙伴系统算法: ```c #include <stdio.h> #include <stdlib.h> #include <math.h> #define MAX_SIZE 1024 // 内存最大大小 #define MIN_SIZE 4 // 内存最小大小 #define FREE 0 // 空闲块 #define BUSY 1 // 忙碌块 struct block { int size; // 块大小 int status; // 块状态 int buddy; // 伙伴块位置 }; static struct block mem[MAX_SIZE]; // 内存块数组 // 打印内存块信息 void print_mem() { int i; printf("Memory Map:\n"); for (i = 0; i < MAX_SIZE; i += mem[i].size) { printf("[%d:%d:%d] ", i, mem[i].size, mem[i].status); } printf("\n"); } // 求以2为底的对数 int log2(int n) { int k = 0; while (n > 1) { n /= 2; k++; } return k; } // 求大于等于n的最小2的幂次方 int ceil2(int n) { return pow(2, ceil(log2(n))); } // 初始化内存块数组 void init_mem() { int i, size; // 初始化内存块 for (i = 0, size = MAX_SIZE; size >= MIN_SIZE; size /= 2) { mem[i].size = size; mem[i].status = FREE; mem[i].buddy = -1; i += size; } } // 合并空闲块 void merge(int p) { int q; // 找到伙伴块位置 q = p ^ mem[p].size; // 判断伙伴块是否为空闲块 if (mem[q].status == FREE && mem[q].size == mem[p].size) { // 合并块 mem[p].size *= 2; mem[q].status = BUSY; mem[p].buddy = -1; mem[q].buddy = -1; merge(p); } } // 分配内存块 int alloc(int size) { int p, q, k; // 找到第一个大小大于等于size的空闲块 for (p = 0; p < MAX_SIZE && (mem[p].size < size || mem[p].status == BUSY); p += mem[p].size); // 如果找到空闲块 if (p < MAX_SIZE) { k = log2(mem[p].size) - log2(size); while (k >= 0) { q = p ^ (1 << k); // 如果伙伴块为空闲块或伙伴块大小小于size,则不再分割 if (mem[q].status == BUSY || mem[q].size < size) { k--; } else { // 分割块 mem[q].status = BUSY; mem[p].buddy = q; mem[q].buddy = p; mem[q].size = mem[p].size / 2; mem[p].size /= 2; k--; merge(p); } } mem[p].status = BUSY; mem[p].buddy = -1; return p; } else { // 没有空闲块可用 return -1; } } // 释放内存块 void free_mem(int p) { int q; mem[p].status = FREE; // 递归合并块 while (p >= 0) { // 找到伙伴块位置 q = p ^ mem[p].size; // 如果伙伴块为空闲块,则合并块 if (mem[q].status == FREE) { // 分割块 mem[p].size *= 2; mem[q].status = BUSY; mem[p].buddy = -1; mem[q].buddy = -1; p = (p < q ? p : q); } else { break; } } } int main() { int p, size; // 初始化内存块数组 init_mem(); // 打印初始内存块状态 print_mem(); // 分配内存 size = 16; p = alloc(size); printf("Alloc %d bytes at position %d.\n", size, p); print_mem(); // 分配内存 size = 32; p = alloc(size); printf("Alloc %d bytes at position %d.\n", size, p); print_mem(); // 释放内存 free_mem(p); printf("Free block at position %d.\n", p); print_mem(); // 分配内存 size = 64; p = alloc(size); printf("Alloc %d bytes at position %d.\n", size, p); print_mem(); return 0; } ``` 以上是伙伴系统算法的C语言实现,可以用来动态分配内存。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值