基于C语言实现操作系统内存管理
♻️ 资源
大小: 1.53MB
➡️ 资源下载:https://download.csdn.net/download/s1t16/87453218
操作系统实验实验二:内存管理
实验目的
在本次实验中,需要从不同的侧面了解 openEuler 的虚拟内存机制。在openEuler 操作系统中,可以通过一些 API 操纵虚拟内存。主要需要了解以下几方面:
- openEuler 虚拟存储系统的组织
- 如何控制虚拟内存空间
- 如何追踪进程内存使用情况
- 详细了解与内存相关的 API 函数的使用
实验要求及内容
创建一个包含两个线程的进程:线程 t1 和线程 t2,进程 p1 通过执行一系列内存操作来模拟内存分配活动,线程 t2 用于跟踪线程 t1 的内存行为,两个线程通过信号量进行同步。
线程 t1 执行的内存操作类型包括:分配虚拟内存、写入虚拟内存、释放虚拟内存、锁定物理内存、解锁物理内存,可以将内存操作编号保存到输入文件中,线程 t1 从输入文件中读取内存操作并执行。
设计的实验需覆盖以下操作序列(可以通过多个输入文件做多个实验来覆盖):
- 分配一块虚拟内存区域,然后打印该区域上的部分或全部内容
- 分配一块虚拟内存区域,然后对该区域执行写入操作
- 释放一块虚拟内存区域,然后打印该区域上的部分或全部内容
- 释放一块虚拟内存区域,然后对该区域执行写入操作
实验设备环境
- openEuler 20.03 (LTS), Linux version 4.19.90-2003.4.0.0036.oe1.aarch64
- gcc (GCC) 7.3.0
实验步骤
本次实验采用了服务器的方式登录openEuler系统,找到以自己学号命名的文件夹,将输入文件 input.txt 与代码文件 memory-op.c 放在同一路径下。
- 编译:gcc memory_op.c -o memory_op -l pthread
- 运行:./memory_op
1.运行样例输入,查看运行情况。
样例输入:
0 0 50 7
1 0 40 7
0 50 40 7
1 50 30 7
2 50 20 7
3 50 10 7
4 50 20 7

从样例输入中我们发现了几个问题
- 物理内存在什么情况下会增加?
- 物理内存增加与释放的大小与申请增加和释放的内存有什么关系?
- 内存释放了之后继续写会发生什么?
- 内存释放已经释放的内存会发生什么?
- 加锁之后对内存进行操作会发生什么?
2.我们修改输入,在释放完内存之后做写操作
此时输入:
0 0 50 7
1 0 40 7
0 50 40 7
4 50 30 7
1 50 20 7

我们发现此时发生了段错误。因此得知,在未分配的内存上做写操作是不被允许的。
3.接着,我们尝试在已经释放的内存上做释放操作,探究会发生什么?
输入修改如下:
0 0 50 7
1 0 40 7
0 50 40 7
4 50 30 7
4 80 30 7
0 100 20 7
4 100 30 7
本次输入修改,有两个目的,一个是同一片内存分两次释放,另一个是释放比分配内存多的部分会发生什么?

我们发现,不论是从哪里开始释放,地址的起始地址都是同一个,这与我们的常理不同,并且释放函数的含义也是从起始开始释放。我们于是查看了源代码,发现此时的打印为

打印的为region,而rigion是指最近分配的内存地址,不符合释放的首地址,我们将其修改如下:
![]()
这样打印的就是此时释放的首地址了。
此外,当我们多释放地址时,此时也没有发生错误。通过查阅资料我们得知,如果释放失败,则会返回-1,于是我们修改如下:

最后运行时仍能正常运行没有报错。因此我们可以判断,当释放已释放的内存时,为合法释放,只是释放内存量为0。
4.脏页提交(物理内存增加)规律
最开始观察老师提供的输入,发现有的时候虽然逻辑内存里的页被修改了,但是并不会被提交即扩大物理内存。通过查阅资料,我们最初认为当写不是同一片连续区域,或者内存被释放时会被提交。但是当测试样例扩大,我们发现如果脏页过少,也不会被提交,于是我们猜测只有脏页到达一定值后才会被提交。



通过控制变量可发现,第一个输入的写没有写到65页,没有被提交,但是第二个第三个第一次写到65页即被提交。所以我们认为我们得出结论第一次脏页达到65页,就可以被提交。第三个输入第三次写65页没有被提交,而第二个输入第三次写66页就可以被提交。所以接着得出结论第一次提交后,后续要被提交脏页的数量一定要达到66页才会被提交。但是测试过程中我们发现,程序如果最后一次为写即使不达到66页依然被提交。

所以我们认为,如果程序最后的操作为写,无论大小为多少,都会被提交。

最后我们印证了,当取消映射时,物理内存会变大,即脏页提交。
通过实验我们粗略得到以下规律:
- 正常情况下脏页被提交,不是以一页为单位,而是为了减少了io次数,提高效率,积攒足够的脏页后才被提交通常该值为65或66
- 进程在映射空间的对共享内容的改变并不直接写回到磁盘文件中,往往在调用munmap()后才执行该操作,物理内存此时会增加。
- 如果最后运行写操作,无论脏页积攒是否达到66或65都会被提交
5.物理地址映射规律
通过多次测试实验样例,修改测试样例我们发现,当虚拟内存开始被提交,线程物理内存变大时,并不总是按照我们预想的,弄脏多少页,物理内存就增加相应的页数,而是总会比该值多出一或三,而且该值会随着运行次数而改变,目前小组成员猜测,逻辑内到虚拟内存的映射也不是以页为单位进行映射,而是多页作为整体来映射,每次映射会比需要的多出几页。但由于每次运行的结果都不同,小组成员,也未能得出准确结论。


6.锁对写操作的影响
小组成员最初,对锁机制的锁没有太明白锁住的是什么,于是对测试样例进行修改得出结论。

通过该输入我们可以发现关于程序的锁机制,实现的是防止这部分内存页被调度到交换空间,实际上对于该程序的操作而言,没有体现锁机制,也就是虽然加了锁,但是写操作等没有用到该特征。
实验心得体会
本次上机总时长约为8小时,花费时间较长。
此次实验小组成员花费时间较长,主要时间花在测试样例的构想,以及对测试结果的分析上。在实验的最开始,小组成员就平台就遇到了问题,因为本次实验输出较多,会造成页的滚动。然而,在vmware的虚拟机上,我们无法做到页的自由滚动。经过数次尝试换平台安装虚拟机无果之后,我们最终需选择了远程登录openEuler系统,完成本次实验。
开始实验后,由于对api的不熟悉,对代码无法理解,不能明白每个参数的含义。通过认真阅读指导书,了解每个api的作用,再通过尝试运行测试样例,理解了每个参数的含义以及输出结果的意义,使得实验可以继续进行。
最初成员理论知识掌握的不充分,对于实验中出现的各种非正常现象无法进行解释,为了解决这个问题,我们构建了大量的输入测试样例,通过控制变量,观察每个不同的变量,依次递增取不同的值会对结果造成怎样的影响,过程中成员通过网络,书籍积极查找资料,对理论知识有了更深层的掌握之后,可以解释每种现象出现背后的原理。
最后,本次实验并不像第一次实验,代码修改的空间很小,任务更多的落在了对测试结果的分析上,然而这就需要扎实的理论基础作为支撑,通过本次试验,小组成员对虚拟内存的理论知识都有了更深层的理解,并且通过实验,可以做到将理论知识运用到实际的应用上,再通过实际运行的结果不断完善自己的理论知识。总之,本次实验虽然花费了成员大量的精力,但是也给成员们带来了不小的收获,以及实验完成的满足感。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)