30天自制操作系统第九天

操作系统实验日志9

第9天:内存管理

一、实验主要内容

1. 内容1:整理源文件

在这里插入图片描述
因为添加了很多c文件,所以我们要修改Makefile文件:

在这里插入图片描述
在这里插入图片描述

2. 内容2:内存容量检查1

1、内存容量检查:

我们在内存管理之前,第一部要做的就是检查内存的容量。我们可以调用BIOS的相关函数来查询,但是因为调用方法等原因过于麻烦==(还有一个原因是我觉得我们现在已经进入了32位模式,而我们的bios是一个16位的程序,前面作者也说了,从16位模式变为32位模式很容易,但是要从32位模式再转为16位模式就要麻烦的多,我猜这也是我们不用该方法的原因)。==

所以我们采用的方法是:先令高速缓存无效(如果有的话),然后向一个地址写入数据,如果该数据能成功从该地址中读取出来,那么就证明我们的地址是可用的。

2、内存检查时关闭缓存的原因:
如果缓存可用,那么我们的写入和读取操作就可能是在缓存中进行的,也就是说我们根本没有对内存进行操作,所以要先关闭缓存。

3、EFLAGS寄存器,见第四次日志
4、memtest函数解析:

在这里插入图片描述

在禁用和恢复高速缓存的时候,我们用到了CR0控制寄存器:
在这里插入图片描述

通过代码可以看到,禁用高速缓存,将CR0寄存器的第29、30位都置为了1,对第30位很容易理解,它是标志着是否使用缓存。但是对于第29位,我没有查到相关信息,所以我也不知道设置它是不是必要的。

加载和设置cr0寄存器的函数只能通过汇编代码来写:
在这里插入图片描述

我觉得这里面值得一提的是在store_cr0函数中,设置cr0寄存器的值的时候,是引入了一个通用寄存器,因为我们不能向cr0这种有特殊功能的寄存器直接写入数据,只能借助一个通用寄存器。

5、memtest_sub函数解析:

在这里插入图片描述

但是这样做,就相当于一个一个内存地址的检查,程序执行的会很慢,改良版就是每次只检查一块内存的最后4个地址:

在这里插入图片描述

3. 内容3:内存容量检查2

1、在主函数中对0x400000到0xbfffffff范围的内存进行检查:
在这里插入图片描述

结果:在这里插入图片描述

查看汇编代码可知原因是,编译器对我们的代码进行了优化,编译器认为如果if语句不执行,将数据反转后再反转没有意义所以它不会去执行,所以根本就没有进行内存检查。

解决方法1:通过使用volatile关键字禁止编译器对指针p进行优化

在这里插入图片描述
在这里插入图片描述

PS:我尝试通过volatile关键字修饰函数,然而编译能成功但是结果却不对,看来volatile关键字只能修饰变量。

解决方法2:用汇编程序来写

4. 内容4:挑战内存管理:内存的分配和释放

内存的分配:假设有128MB内存,即0x8000000个字节

方法1:以4KB为单位进行管理,维持一个数组,数组的值标记对应的4kb是否为空。

举例:以4kb为单位,即分为0x800000/0x1000=32768个区域

在这里插入图片描述

需要多少空间,就算出来需要连续的区域的个数,即连续的标记为0的个数的区域。

在这里插入图片描述

然后再将这些区域标记为1,表示已经被使用:

在这里插入图片描述(可以看出来,这种方法都是将我们想要存储的东西连续储存,也就是需要连续的地址)

额外空间开销:地址被分为几个区域就需要几个字节来储存,额外的空间占容量的0.02%。

方法2:用一个bit来存储区域是否被使用,这样空间开销是容量的0.003%。

方法3:列表管理,用一个结构体来表示一个连续区域的可用状况,有开始地址以及大小,用一个结构体进行内存管理,描述可用的连续区域的个数以及每个连续区域的可用状况。
在这里插入图片描述

需要一个空间,就扫描这些可用区域的size大小,直到找到一个大小满足要求的区域,然后将size减去即将被使用的部分,开始地址变为新区域的首地址。如果size减为0,那么就将这条信息从结构体中删除。释放内存时,则增加一条可用信息,还要看他们可不可以和前后的空间连在一起。

优点: 1、占用内存小,假如分1000个条目,那么内存管理仅需要1000*8+4=8004个字节。2、处理更快,占用内存时,只需要加法(原地址加上使用的空间)和减法运算(size减去使用的空间)各执行一次,释放空间也比逐一将0写入内存快得多。

缺点: 会造成外部碎片,也就是使用这种方法时间变长,内存就会被分的零零散散。

代码分析:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

主函数:

在这里插入图片描述

二、遇到的问题及解决方法

1.描述问题1:在memtest_sub函数中,检查是否写入到内存时,为什么要先将写入的数据反转在检查比较?

解决方法: 需要写入数据再反转是因为有些机型由于芯片组和主板电路等原因,如果不做这种检查就会直接读出写入的数据,所以要反转一下。

2.描述问题2:一次只检查4kb内存的最后4个地址,不免会有疑问,如果不可使用的内存正好处于这4kb之间怎么办?

解决方法: 其实无需担心这个问题,因为在系统启动的时候内存已经被检查过了,像存储了bios这样的我们不能使用的内存都是连续的而且占用比较大,所以我们能使用的部分也是一整块,我们检测的其实就是它的上界和下界。

三、程序设计创新点

1、描述创新点1: 在内存的释放函数中,如果不可与前后合并而文件管理列表又满了,作者的做法是暂时不注册要释放的部分,我的做法是将表示最小的的那部分管理列表空出来来保存我们释放的这部分。

在这里插入图片描述

四、实验心得体会

本次实验对我们自己制作的系统进行了内存管理,首先先对内存进行检查,获得可用内存的容量,最后采用的内存管理的方法是列表管理的方法,也就是维护那么一个记录可用内存的起始地址以及容量的表格,需要用内存的时候就去这个表格里面找到足够大的部分。但是这样很容易造成外部碎片,也就是剩余的空间总大小很大,但是都是零零碎碎的,我猜下一步就是对这个的优化,但是想一想我们文件的变化过程,我们都是使用的作者写的编译器,我们得到的二进制文件并不是可重定位目标文件,所以我们应该还没有虚拟地址这个概念,现在谈分页可能还早点,希望可以早点讲到分页管理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值