第九天,咱们来说说内存管理。
很明显的,再次感受到《数据结构》的重要性。
首先我们来进行内存检查,即确定内存容量。用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; /* 失敗終了 */ }