操作系统原理实验:动态分区分配方式(魔改版first fit(首次适应)算法和best fit(最佳适应)算法)

实验目的

了解动态分区分配方式中使用的数据结构和分配算法,进一步加深对动态分区存储管理方式及其实现过程的理解。提高设计实验、发现问题、分析问题和解决问题的能力,并学习撰写规范的科学研究报告。

内容和要求

1.用C或其他语言分别实现动态分区分配过程和回收过程。
2.设置初始状态,每次分配和回收后显示出空闲内存分区链的情况。

实验原理

(1)first fit(首次适应)算法 · 魔改。

现代计算机系统为了确保安全性,操作系统均引入了ASLR(地址空间布局随机化),并与MMU的更复杂的地址翻译机制配合,使得数据在内存中的分布显得随机。
为了模拟得更接近较新的操作系统的动态内存分配与回收机制,这里不模拟通过first fit和best fit算法直接进行顺序查找并分配内存,而是模拟用户调用malloc、new等内存分配的函数或运算符之后,从线性地址已经转换为物理页号(PPN)的时刻开始,直到返回随机分配的物理页号,这一段分配过程(因为一旦随机找到一片满足要求的可用空间就立即分配,所以这里其实借鉴了first fit的思想)。
本程序通过< random >中的随机数生成引擎std::mt19937_64随机生成物理页号来简单模拟MMU将线性地址转换为内存的物理地址并取得物理页号的过程,并用两个std::map——free_list和used_list模拟由操作系统内核维护的空闲列表。页大小设为4 KB。
本程序通过模拟对内存的按页分配来演示内存分配与释放的过程。内存空间一次至少分配一页,并在成功分配后修改空闲列表free_list和已使用列表used_list。在回收已分配的内存页时,这两个表也要修改。物理内存的第0页设为不可访问,当没有足够大的连续内存空间可供分配时,页号就返回0,代表分配失败。
如果随机查找到页数比需要的页数大的内存空间,那么在这段内存空间中随机选取一段连续的页进行分配。
每次释放内存后,当空闲列表free_list上有两个相邻节点表示的物理内存空间连续时,为了减少查找空闲列表的耗时,这两个节点要合并。
这里不用线性表或链表来构造空闲列表,是因为需要频繁插入、删除、查找:在线性表上查找、插入、删除元素的时间复杂度和在链表上查找的时间复杂度均达到O(n)。本实验选用的std::map是用红黑树实现的。如果使用std::map来构造空闲列表,那么随机分配和释放内存时,时间复杂度均减小到O(log n)。当内存不足时,由于分配内存需要遍历该表,时间复杂度为遍历红黑树的均摊时间复杂度O(n);但回收已使用内存时,时间复杂度仍然为O(log n)。
使用used_list是为了模拟内存的释放。used_list也用红黑树存储,方便每次分配或回收时按低地址(0x0)到高地址的顺序输出内存空间的使用情况。模拟内存回收在模拟内存分配之后进行。全部的已使用空间的地址会通过std::shuffle打乱顺序,然后按此顺序释放内存。
尝试随机分配最多10次(可以在代码中修改尝试次数max_attempt_count)。如果随机查找空闲列表10次都未找到足够大的连续内存空间来分配这些页,就认为可用的连续内存空间已经不足,此时将遍历整个空闲列表尝试分配。当第一次找到足够的空间后,就分配内存(first fit);如果遍历完毕后仍然找不到符合要求的空闲内存,则分配失败。
每次分配和回收后,都显示空闲内存和已用内存的情况。
由于篇幅所限,在本实验中不模拟内存碎片的回收机制。

(2)best fit(最佳适应)算法 · 魔改。

这一部分的很多代码可以直接套用(1)中的代码,但也有地方需要修改。
首先free_list的数据结构采用std::multimap,且以页数为索引。也就是说第一项为页数,第二项为这段连续的内存空间的起始地址。分配内存的时候,根据所需的页大小可以以O(log n)的时间复杂度取得一段尽可能小的连续的内存空间,减少内存碎片。当这段内存空间的页数更多时,同样随机选取其中一段连续的页面进行分配。如果搜索不到长度达到所需页数的连续内存空间,则直接返回分配失败。
used_list的含义与(1)相同。
当释放内存时,由于空闲列表不是按起始地址索引的,而是按页数索引的,所以需要遍历全表来判断在将释放的内存对应的节点重新写入空闲列表后,是否有节点刻画的空闲内存与这段刚释放的空间相邻。如果是,则合并节点。释放内存的时间复杂度为遍历整个红黑树的均摊时间复杂度,即O(n)。
输出内存情况的函数只需做少量的修改即可。

代码

横向长度较长,建议先将代码复制到IDE中,然后将IDE的窗口最大化,再进行查看。
(1)first fit

#include<iostream>
#include<map>
#include<algorithm>
#include<vector>
#include<random>
#include<chrono>
#include<string>
#include<iomanip>
#include<cmath>
#include<cstdint>
using namespace std;

const size_t memory_capacity = 1ull << 33;
const size_t page_count = memory_capacity / 4096; //Page size = 4 KB
const size_t bound[] = {
    1ull, 1ull << 8, 1ull << 18, 1ull << 28, 1ull << 38, 1ull << 48 };
const size_t page_to_byte = 1ull << 12;
const char* const unit[] = {
    " KB ", " MB ", " GB ", " TB ", " PB ", " EB " };
const size_t exp_count = 1024;

map<size_t, size_t> free_list, used_list; //The first is starting address, the second is page count.
const pair<size_t, size_t> entire_memory = {
    1, page_count - 1 }; string output_str;

vector<size_t> free_seq;
uniform_int_distribution<size_t> us(1, page_count - 1), upe(2, UINT64_MAX); mt19937_64 re; //Random engine.

//Modify the node of the free list and the used list according to the random situation of allocation.
inline size_t split_node_n_mark_used(const map<size_t, size_t>::iterator& i, size_t _PageCount) {
   
	static pair<size_t, size_t> p, q, r;
	p.first = us(re) % (i->second - _PageCount) + i->first; p.second = _PageCount;
	if (p.first == i->first) {
   
		q = {
    p.first + p.second, i->second - _PageCount }; free_list.erase(i); free_list.emplace(q);
	}
	else if (p.first + p.second == i->first + i->second) {
   
		q = {
    i->first, i->second - _PageCount }; free_list.erase(i); free_list.emplace(q);
	}
	else {
   
		q = {
    i->first, p.first - i->first }; r = {
    p.first + p.second, i->second - q.second - _PageCount };
		free_list.erase(i); free_list.emplace(q); free_list.emplace(r);
	}
	used_list.emplace(p); return p.first;
}

//Allocate specific free memory.
inline size_t alloc(const map<size_t, size_t>::iterator& i, size_t _PageCount) {
   
	static size_t s; s = us(re);
	if (i->second == _PageCount) {
    s = i->first; used_list.emplace(*i); free_list.erase(i); return s; } //Allocation succeeded.
	else {
    s = i->first; return split_node_n_mark_used(i, _PageCount); } //Allocation succedded.
}

//Allocate a segment of free memory.
inline size_t random_alloc(size_t _PageCount) {
   
	static const size_t max_attempt_count = 10; static size_t s; static map<size_t, size_t>::iterator i;
	for (size_t h = 0; h < max_attempt_count; ++h) {
   
		s = us(re); i = free_list.lower_bound(s); if (i == free_list.end())--i;
		if (i->second == _PageCount) {
    s = i
  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值