1 伙伴系统
- 与边界标志法相比没有尾信息
- 分配内存块大小: 2n
- 由同一个内存块分割成的两个完全相等的内存块互为伙伴。
- 内存碎片化严重
- 回收时必须互为伙伴才能合并
不是伙伴,无法确定另一个内存块的边界
2 C语言实现
2.1 头文件
#pragma once
#define M 16
typedef struct Word
{
struct Word* llink;
int tag;
int kval;
struct Word* rlink;
}Word, * Space;
typedef struct HeadNode
{
int nodesize;
Word* first;
Word* start;
}FreeList[M+1];
Space CreateMem();
void InitSqlist(FreeList& avail,Space p);
Word* AllocBuddy(FreeList& avail, int n);
void Free(FreeList& avail, Space p);
2.2 创建内存池
#include"buddy.h"
#include<stdio.h>
#include <malloc.h>
#include<math.h>
#include <cassert>
Space CreateMem()
{
Word* pmem = (Word*)malloc((int)pow(2, M) * sizeof(Word));
assert(pmem != NULL);
pmem->llink = pmem;
pmem->rlink = pmem;
pmem->tag = 0;
pmem->kval = M;
return pmem;
}
2.3 初始化内存映射顺序表
void InitSqlist(FreeList& avail,Space p)
{
avail[0].start = p;
for (int i = 0; i <= M; i++)
{
avail[i].first = NULL;
avail[i].nodesize = 0;
}
int k = p->kval;
avail[k].first = p;
avail[k].nodesize = (int)pow(2, k);
}
2.4 分配内存单元
2.4.1 从内存映射表中删除该内存单元
static void Delete(FreeList& avail, Space p)
{
Word* front = p->llink;
Word* rear = p->rlink;
if (p == rear)
{
avail[p->kval].first = NULL;
}
else
{
front->rlink = rear;
rear->llink = front;
avail[p->kval].first = rear;
p->llink = p;
p->rlink = p;
}
}
2.4.2 分配内存单元,将剩余空间分裂
Word* AllocBuddy(FreeList& avail, int n)
{
Word* p = NULL;
for (int k = 0; k <= M; ++k)
{
if (k > M)
{
return NULL;
}
else if (avail[k].nodesize >= n && avail[k].first != NULL)
{
p = avail[k].first;
Delete(avail, p);
int i = 1;
if (p->kval > 0 && avail[k].first == NULL)
{
while ((int)pow(2, k - i) >= n)
{
Word* pi = p + (int)pow(2, k - i);
pi->rlink = pi;
pi->llink = pi;
pi->tag = 0;
pi->kval = k - i;
avail[k - i].first = pi;
avail[k - i].nodesize = (int)pow(2, pi->kval);
i++;
}
}
p->llink = p;
p->rlink = p;
p->tag = 1;
p->kval = k-(--i);
break;
}
}
return p;
}
2.5 回收内存
2.5.1 判断要回收的内存单元是左块还是右块
static Word* RorL(FreeList& avail,Space p)
{
int tmp = p - avail[0].start;
int flg = tmp % (int)pow(2, p->kval + 1);
if (flg != 0)
{
return p - (int)pow(2, p->kval);
}
else
{
return p + (int)pow(2, p->kval);
}
}
2.5.2 将内存单元和顺序表映射
static void Insert(FreeList& avail, Space p)
{
if (avail[p->kval].first == NULL)
{
avail[p->kval].first = p;
p->tag = 0;
}
else
{
Word* q1 = avail[p->kval].first;
Word* front = q1->llink;
q1->llink = p;
front->rlink = p;
p->llink = front;
p->rlink = q1;
p->tag = 0;
}
}
2.5.3 判断顺序表是否为空
bool IsEmpty(FreeList& avail)
{
for (int i = 0; i <= M; i++)
{
if (avail[i].first != NULL)
{
return false;
}
}
return true;
}
2.5.4 判断伙伴,进行内存单元的回收合并
static void Free_mask(FreeList& avail, Space& p)
{
Space pi = RorL(avail, p);
if (pi->tag == 1)
{
Insert(avail, p);
}
else if (pi->tag == 0 && pi->kval != p->kval)
{
Insert(avail, p);
}
else
{
Delete(avail, pi);
p->tag = 0;
if (p > pi)
{
p = pi;
}
p->kval++;
}
}
void Free(FreeList& avail, Space p)
{
if (!IsEmpty(avail))
{
p->tag = 0;
Space q = p;
int k = p->kval;
while (p->tag == 0 && p->kval == k)
{
Free_mask(avail, p);
k++;
}
if (p->kval == M - 1)
{
q->kval--;
avail[q->kval].first = NULL;
q = q - (int)pow(2, q->kval);
avail[M].first = q;
q->llink = q;
q->rlink = q;
q->kval = M;
q->tag = 0;
}
}
else
{
avail[p->kval].first = p;
p->tag = 0;
}
}