通过在创建进程实验基础上实现进程的分页式内存分配和地址转换过程,完成请求分页式存储分配和地址转换过程,掌握页面置换算法。通过请求分页存储管理的设计,让学生了解虚拟存储器的概念和实现方法。在运行的过程中若要访问的页面不在内存时,则需求有请求调入的功能将其调入。假如此时若内存没有空白物理块,则通过页面置换的功能将一个老的不用的页面淘汰出来,其中淘汰的算法有多种。
1.建立一个位示图,用来模拟内存的分配情况,位示图的位数与设定的物理块个数相同。程序启动时可利用一组随机0和1填充位示图,表示内存已被占用情况。
2.创建进程时输入进程大小,并根据程序中设定的物理块大小为进程分配物理块,同时建立支持请求和置换功能的二维页表(增加存在位等)页表。
3.输入当前执行进程所要访问的逻辑地址,并将其转换成相应的物理地址。
4.进程退出时,根据其页表内容向位示图反向回填“1”。
5.创建进程时可装入固定的前三页(或键盘输入初始装入页数,不同进程的装入个数可以不同),其余页装入到置换空间内。
6.选下列其一:先进先出(FIFO)、最近最久未使用(LRU)、CLOCK等置换算法对地址转换过程中遇到的缺页现象进行页面置换,可将多次地址转换过程中所涉及到的页号视为进程的页面访问序列,从而计算置换次数和缺页率。
1.不同的功能使用不同的函数实现(模块化),对每个函数的功能和调用接口要注释清楚。对程序其它部分也进行必要的注释。
2.对系统进行功能模块分析、画出总流程图和各模块流程图。
3.用户界面要求使用方便、简洁明了、美观大方、格式统一。所有功能可以反复使用,最好使用菜单。
4.通过命令行相应选项能直接进入某个相应菜单选项的功能模块。
5.所有程序需调试通过。
1、首先表示出内存的初始状态,使用随机0和1组成的一个数组表示它的初始状态。
2、然后,实现进程的创建,模拟系统给它分配空的内存块。
3、最后,通过地址转换,将访问的逻辑地址转换成要访问的页号,遇到缺页现象,通过LRU置换算法将最近最久未使用的进程块置换出来,并计算出缺页率。
import random
def init_bit_map(num_phycial):#使用随机的0和1去初始化内存状态
bit_map = [random.randint(0,1) for _ in range(num_phycial)]
return bit_map
def create_process(process_size,page_size,bit_map):
num_process_table = process_size // page_size
process_table = []
for idx,value in enumerate(bit_map):
if value == 0:
bit_map[idx] = 1
process_table.append(idx)
if len(process_table) == num_process_table:
break
if len(process_table) < num_process_table:
for i in process_table:
bit_map[i] = 0
process_table = []
print("内存空间不足!创建进程失败")
return process_table
def translate(access_table,page_size,process_table):
Orderaccess = []
for i in access_table:#转换为物理地址
Orderaccess.append(process_table[i//page_size]*page_size+i%page_size)
return Orderaccess
#模拟寻找物理地址的页
def imitate(physical_address,page_size):
return physical_address//page_size
class LRUPageReplacement:
def __init__(self, physical_allocation):
self.frames = [None for _ in range(physical_allocation)]
self.last_used = [0 for _ in range(physical_allocation)]
self.init_time = 1
self.miss_counts = 0
self.page_table = []
self.exist = []#存在位
self.times = []
# 页面置换
def page_replace(self, page_number):
if page_number not in self.frames:
min_last_used = min(self.last_used)#获取最久未使用的块
frame_number = self.last_used.index(min_last_used)
self.frames[frame_number] = page_number
# self.init_time += 1
self.last_used[frame_number] = self.init_time
self.miss_counts += 1
self.page_table.append(self.frames.copy())
self.exist.append(False)
else:
self.last_used[self.frames.index(page_number)] = self.init_time
self.page_table.append(self.frames.copy())
self.exist.append(True)
def update_last_used(self):#更新时间
self.init_time += 1
self.times.append(self.last_used.copy())
def show_page_table(self):
for idx in range(len(self.page_table)):
print(*self.page_table[idx],end=" ")
print(self.exist[idx])
# print(self.times[idx])
print("缺页次数:"+str(self.miss_counts))
print("缺页率为:"+str(self.miss_counts/len(self.page_table)))
if __name__ == '__main__':
num_physical = int(input("请输入物理块的个数:"))
page_size = int(input("请输入页的大小:"))
#随机生成bit_map,模拟内存状态
bit_map = init_bit_map(num_physical)
print("此时内存块的状态为:"+str(bit_map))
physical_allocation = 3
process_size = int(input("请输入要执行进程的大小:"))
#模拟进程存储
process_table = create_process(process_size,page_size,bit_map)
# print(process_table)
access_table = []
while True:
value = input("请输入要访问的进程逻辑地址(输入exit结束):")
if value == "exit":
break
elif int(value) > process_size:
print("输入的逻辑地址大于进程大小")
else:
access_table.append(int(value))
# print(access_table)
access_table = translate(access_table,page_size,process_table)
LRU = LRUPageReplacement(physical_allocation)
Order = []
for i in access_table:
page = imitate(i,page_size)
Order.append(page)
LRU.page_replace(page)
LRU.update_last_used()
print("访问顺序为:"+str(Order))
LRU.show_page_table()