第九天,咱们来说说内存管理。
很明显的,再次感受到《数据结构》的重要性。
首先我们来进行内存检查,即确定内存容量。用memtest函数实现。在确定容量前,首先要暂时让486以后的CPU的cache功能无效。为了确定CPU是386还是486以上,利用二者eflag的18位即可判断。486以上是AC标志位,386没有此位。因此把1写到此为后再读出检验,若是1则是486以上,若是0,则是386。接下来,memtest_sub具体实现确定容量的工作。它的功能是调查从start地址到end地址的范围内,能够使用的内存的末尾地址。并且注意一点,这个检查程序被编译器误读,应该由汇编语言编写。
内存检查完了,接下来该管理了。内存管理的基础,一是内存分配,一是内存释放。
作者和我们一起探究了寻找较好的管理方式的方法。我觉得这个过程也是很有启发性的,所以不能只是简单地总结最后的选择。
方法一)作者提出最简单的管理方法。我们把所有内存单元以4KB为单位分割。然后建立数组。若已用,值为1;若未用,值为0。这种方法很简单,但是有很大的压缩空间。因为记录一个单元的状态的只有0,1两种,也就是说1位就够了。这就是方法二。
方法三)采用列表管理的方法,把类似“从xx号地址开始的yy字节是空的”这种信息都列在表里。这种方法不仅省内存,而且在分配和释放大块内存时都很迅速。
方法四)方法三有一个缺点,当可用空间被搞得零零散散,怎么都归纳不到一块儿时,会将1000条可用空间管理信息全部用完。方法四在方法三的基础上,若发生管理空间用完现象,则割舍掉小块内存,等有空余后,再找回来。
具体的alloc和free的函数,还是要看源程序,并且注意一些细节问题。如在分配时,若正好用完,则减少一条可用信息。又如在释放时,若连着头,则归到上一条,连着尾则归到下一条,若头尾都连,则连尾一起归到头,若头尾都不连,则新插入一条信息。实际操作起来是很容易写错的哦,可以自己试试看。
此处附上源程序:
struct FREEINFO { /* あき情報 */
unsigned int addr, size;
};
struct MEMMAN { /* メモリ管理 */
int frees, maxfrees, lostsize, losts;
struct FREEINFO free[MEMMAN_FREES];
};
unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)
/* 確保 */
{
unsigned int i, a;
for (i = 0; i < man->frees; i++) {
if (man->free[i].size >= size) {
/* 十分な広さのあきを発見 */
a = man->free[i].addr;
man->free[i].addr += size;
man->free[i].size -= size;
if (man->free[i].size == 0) {
/* free[i]がなくなったので前へつめる */
man->frees--;
for (; i < man->frees; i++) {
man->free[i] = man->free[i + 1]; /* 構造体の代入 */
}
}
return a;
}
}
return 0; /* あきがない */
}
int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)
/* 解放 */
{
int i, j;
/* まとめやすさを考えると、free[]がaddr順に並んでいるほうがいい */
/* だからまず、どこに入れるべきかを決める */
for (i = 0; i < man->frees; i++) {
if (man->free[i].addr > addr) {
break;
}
}
/* free[i - 1].addr < addr < free[i].addr */
if (i > 0) {
/* 前がある */
if (man->free[i - 1].addr + man->free[i - 1].size == addr) {
/* 前のあき領域にまとめられる */
man->free[i - 1].size += size;
if (i < man->frees) {
/* 後ろもある */
if (addr + size == man->free[i].addr) {
/* なんと後ろともまとめられる */
man->free[i - 1].size += man->free[i].size;
/* man->free[i]の削除 */
/* free[i]がなくなったので前へつめる */
man->frees--;
for (; i < man->frees; i++) {
man->free[i] = man->free[i + 1]; /* 構造体の代入 */
}
}
}
return 0; /* 成功終了 */
}
}
/* 前とはまとめられなかった */
if (i < man->frees) {
/* 後ろがある */
if (addr + size == man->free[i].addr) {
/* 後ろとはまとめられる */
man->free[i].addr = addr;
man->free[i].size += size;
return 0; /* 成功終了 */
}
}
/* 前にも後ろにもまとめられない */
if (man->frees < MEMMAN_FREES) {
/* free[i]より後ろを、後ろへずらして、すきまを作る */
for (j = man->frees; j > i; j--) {
man->free[j] = man->free[j - 1];
}
man->frees++;
if (man->maxfrees < man->frees) {
man->maxfrees = man->frees; /* 最大値を更新 */
}
man->free[i].addr = addr;
man->free[i].size = size;
return 0; /* 成功終了 */
}
/* 後ろにずらせなかった */
man->losts++;
man->lostsize += size;
return -1; /* 失敗終了 */
}