Lab2-1-Extra——一个可能的解决思路
题目要求对物理空间的高32MB地址空间建立伙伴关系,我在这里简单梳理一下我基于数组的实现,由于课上构思比较紧张,代码有些写的不妥的地方请海涵。
首先建立用于存储区间信息的结构体:
typedef struct Buddy{
u_int start;
u_int size;
u_int time;
u_int mode;
u_int f;
}Buddy;
Buddy buddy[100000];
int tot;
int time;
其中,start代表该区间的起始位置;
size代表区间大小;
time是一个比较特殊的量,记录该区间是第几次分裂而来,初始化为0;
mode代表区间状态,1代表已分配,0代表未分配,还有-1会表示一个比较特殊的状态(已分裂),后续会详细解释;
f也是一个比较特殊的量,记录着该区间是由数组中那个元素分裂而来,初始化为-1;
tot记录目前boddy的个数,初始化为0。
这里buddy数组我预留了100000,比较保守。
buddy_init
的思路:
只需要从 0x2000000以起始位置实现8个buddy并存入数组中即可。
void buddy_init(void) {
u_int start = 0x2000000;
u_int size = 0x400000;
int i;
tot = 8;
time = 0;
for (i = 0; i < 8; i++) {
//一些初始化操作
}
//printf("buddy init finish");
}
buddy_alloc
的思路:
大体分为3步:
-
寻找符合要求的地址最低的区间
-
针对该区间进行分裂操作
-
获取各种需要的信息并返回
int buddy_alloc(u_int size, u_int *pa, u_char *pi) {
u_int min = 0x4000010;
int index = 0;
int i;
for (i = 0; i < tot; i++) {
//(1)寻找符合要求的地址最低的区间
}
if (min == 0x4000010) {
//没找到
return -1;
}
int pos = findMin(index, size);//(2)进行分裂操作
//(3)获取输出信息
return 0;
}
可以看到,上述比较关键的是进行分裂操作的函数,此处我写的是一个findMin
递归函数,核心就是将区间分裂,但不删除旧的区间,仅在数组最后添加新的子区间,并标记旧区间的状态为-1,新子区间的f记为旧区间的下标,更新time并标记到新增子区间。
int findMin(int i, u_int size) {
if (buddy[i].size / 2 < size || buddy[i].size == 0x1000) {
buddy[i].mode = 1; //(1)找到了合适的区间
return i;
}
time++;
//(2)新增两个子区间
return findMin(tot-2, size);//递归分裂
}
buddy_free
的思路:
分两步:
1.寻找满足起始地址为pa的区间并改变其状态为未分配
2.合并可能合并的区间
void buddy_free(u_int pa) {
int i;
//(1)寻找满足条件的区间,采用倒序,效率高一些
for (i = tot - 1; i >= 0; i--) {
if (buddy[i].mode == 1 && buddy[i].start == pa) {
break;
}
}
buddy[i].mode = 0;
//(2)合并可能的区间
if (buddy[i].time != 0) {
merge(buddy[i].time);
}
}
上述的关键也是merge
函数,本处我是递归实现的:
void merge(u_int time) {
int a = -1, b = -1, i;
int flag = 0;
//获取两个可能可以合并的区间
for (i = tot - 1; i >= 0; i--) {
if (buddy[i].mode == 0 && buddy[i].time == time) {
if (a == -1) {
a = i;
} else {
b = i;
flag = 1;
break;
}
}
}
if (flag) {
buddy[a].mode = -1;
buddy[b].mode = -1;
//唤醒他们的父区间,并让两个子区间进入异常态实现舍去。
buddy[buddy[a].f].mode = 0;
if ( buddy[buddy[a].f].time != 0) {
merge(buddy[buddy[a].f].time);
//递归合并可能的区间
}
}
}
总结:
对于本题,我采用了数组实现的方法,为了避免TLE,想到了分裂时并不删除区间的方法,其实是以空间换时间,或许可以尝试链表实现的方法,可能更优雅和高效。