一、内存容量检查
1.如何进行内存检查?
往内存中随便写入一个值,然后马上读取,来检查读取的值与写入的值是否相等
2.为了实现直接写入内存的功能,需要先暂时关闭CPU中的告诉缓存
代码如下:
#define EFLAGS_AC_BIT 0x00040000
#define CR0_CACHE_DISABLE 0x60000000
unsigned int memtest(unsigned int start, unsigned int end) //设置内存检查的起始位置
{
char flg486 = 0; //486标志位,只有486以后的cpu才有告诉缓存
unsigned int eflg, cr0, i;
/* 386か、486以降なのかの確認 */
eflg = io_load_eflags(); //读取eflags寄存器
eflg |= EFLAGS_AC_BIT; /* AC-bit = 1 ,将AC位置1*/
io_store_eflags(eflg); //重新载入eflags寄存器的值到cpu中
eflg = io_load_eflags(); //读取eflags的值
if ((eflg & EFLAGS_AC_BIT) != 0) { /* 如果是386,即使设定AC=1,cpu还是会将AC的值自动回到0 */
flg486 = 1; //如果AC位没有回到0,说明是486及以上的cpu
}
eflg &= ~EFLAGS_AC_BIT; /* AC-bit = 0,将AC位置0 */
io_store_eflags(eflg); //重新载入eflags的值到cpu中
if (flg486 != 0) {
cr0 = load_cr0(); //汇编语言编写的函数,读取cr0的值到eax中
cr0 |= CR0_CACHE_DISABLE; /* 禁止缓存 */
store_cr0(cr0); //汇编语言编写的函数,将eax的值存入到cr0中
}
i = memtest_sub(start, end); //内存检查
if (flg486 != 0) { //检查完成后开启CPU的高速缓存功能
cr0 = load_cr0();
cr0 &= ~CR0_CACHE_DISABLE; /* 开启缓存 */
store_cr0(cr0);
}
return i;
}
//功能:内存检查主函数,将一个数值写入到内存并读取,判断两者是否相等
unsigned int memtest_sub(unsigned int start, unsigned int end)
{
unsigned int i, *p, old, pat0 = 0xaa55aa55, pat1 = 0x55aa55aa;
for (i = start; i <= end; i += 0x1000) { //每次增加4kb,相当于一次检查4kb
p = (unsigned int *) (i + 0xffc); //只检查末尾4个字节(为什么?)
old = *p; /* 先记住修改前的值 */
*p = pat0; /* 将一个数值写入内存 */
*p ^= 0xffffffff; /* 将数值的结果反转,1变成0,0变成1*/
if (*p != pat1) { /* 检查反转结果*/
not_memory:
*p = old; //如果不正确,恢复变量
break; //跳出循环
}
*p ^= 0xffffffff; /*如果相等就再次反转*/
if (*p != pat0) { /*判断和最初写出的值是否相等*/
goto not_memory; //不正确后的操作
}
*p = old; /*如果正确,恢复变量*/
}
return i; //如果内存检查过关,返回值应该是最后的地址值
//如果检查过程出现错误,返回值是对应的内存地址
}
二、挑战内存管理
1.什么是内存管理?--内存分配、内存释放
要实现上述功能,首先需要准确记录当前内存的状态,书中使用了两个结构体变量
struct FREEINFO { /* 记录内存信息 */
unsigned int addr, size; //从addr开始的地址算起,有多少位是可用的
};
struct MEMMAN { /* 实现内存管理 */
int frees, maxfrees, lostsize, losts; //frees表示可用的内存信息个数
struct FREEINFO free[MEMMAN_FREES];
};
2.这两个结构体变量如何实现内存管理?
首先由FREEINFO记录可用的内存信息,然后MEMMAN中会记录所用这些可用内存信息
当需要空间时,只要查看MEMMAN中的free的状况,从中找出对应的大小即可,同时进行相应的标注
当空间释放时,增加一条可用信息(需判断能不能与相邻的可用空间连到一起,如果可以就归为一条)
代码如下:
void memman_init(struct MEMMAN *man)
{
man->frees = 0; /* 可用信息的数目 */
man->maxfrees = 0; /* 用于观察可用状况,frees的最大值*/
man->lostsize = 0; /*释放失败的内存的大小总和*/
man->losts = 0; /*释放失败次数*/
return;
}
unsigned int memman_total(struct MEMMAN *man)
/*报告空余内存总大小*/
{
unsigned int i, t = 0;
for (i = 0; i < man->frees; i++) {
t += man->free[i].size;
}
return t;
}
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) { //如果分配后大小为0了,则删除此项条目
man->frees--; //条目数减1
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;
//决定收回的内存应该放在那里,按照地址的大小依次排列
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]之后的记录向后挪动1位 */
for (j = man->frees; j > i; j--) {
man->free[j] = man->free[j - 1];
}
man->frees++; //可用条目加1
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; /* 失敗 */
}