第1题(存储管理_内存碎片)
请指出内部碎片与外部碎片的区别。
ANS:
内部碎片是分配给进程但未被进程使用且无法被其他进程利用的内存空间
外部碎片是内存中因进程分配释放内存形成的不连续小块,虽总和够但因不连续无法分配给需要连续内存的进程。
第2题(存储管理_内存分配算法)
给定六个内存分区,分别为 100M,170M,40MB,205MB, 300MB 和 185MB (按顺序)。
首次适应、最优适应和最差适应算法将如何放置大小为 200MB、15MB、185MB、75MB、175MB 和 80MB (按顺序) 的进程?
指出哪个请求 (如果有) 不能得到满足。评论每种算法管理内存的效率。
ANS:
1.如何放置
首次适应算法:按地址顺序查找,找到第一个能满足进程大小的空闲分区。
对于 200MB 进程,分配 205MB 分区,剩余 5MB。
15MB 进程分配 40MB 分区,剩余 25MB。
185MB 进程分配 185MB 分区,无剩余。
75MB 进程分配 100MB 分区,剩余 25MB。
175MB 进程分配 300MB 分区,剩余 125MB。
80MB 进程分配 170MB 分区,剩余 90MB。所有进程都能满足。
最优适应算法:从空闲分区列表中选择能满足进程需求且最小的空闲分区。
200MB 进程分配 205MB 分区,剩余 5MB。
15MB 进程分配 40MB 分区,剩余 25MB。
185MB 进程分配 185MB 分区,无剩余。
75MB 进程分配 100MB 分区,剩余 25MB。
175MB 进程分配 175MB 分区,无剩余(从 170MB 和 185MB 中选择更合适的 175MB 分区)。
80MB 进程分配 85MB 分区,剩余 5MB。所有进程都能满足。
最差适应算法:从空闲分区列表中选择最大的空闲分区来满足进程需求。
200MB 进程分配 300MB 分区,剩余 100MB。
15MB 进程分配 185MB 分区,剩余 170MB(选择最大的空闲分区 185MB)。
185MB 进程分配 170MB 分区,无法满足(因为之前 15MB 进程分配了 185MB 分区后剩余的 170MB 不够 185MB)。
75MB 进程分配 100MB 分区,剩余 25MB。
175MB 进程分配 205MB 分区,剩余 30MB。
80MB 进程分配剩余的 100MB 分区,剩余 20MB。
2.是否满足
首次适应算法:进程都能满足,分配后剩余分区分别为 5MB、25MB、0、25MB、125MB、90MB。
最优适应算法:进程都能满足,分配后剩余分区分别为 5MB、25MB、0、25MB、0、5MB。
最差适应算法:185MB 进程不能满足,分配后剩余分区分别为 100MB、170MB、0、25MB、30MB、20MB。
3.效率评论
首次适应算法简单,容易产生外部碎片;最优适应算法能较好利用内存空间,但分配和回收操作较复杂,可能产生较多外部碎片;最差适应算法会使大的空闲分区快速被分割变小,可能导致后续大进程无法分配,也容易产生外部碎片。
第三题(存储管理_分页)
假设页大小为 1KB, 以下地址引用 (以十进制数形式提供) 的页码和偏移量是多少?
a. 21205
b. 164250
c. 121357
d. 16479315
e. 27253187
ANS:
在分页存储管理中,页大小为 1KB = 2^10B,所以地址的二进制的低 10 位为偏移量,其余高位为页码。
对于 21205,21205 / 1024 = 20(页码),21205 % 1024 = 725(偏移量)。
对于 164250,164250 / 1024 = 160(页码),164250 % 1024 = 610(偏移量)。
对于 121357,121357 / 1024 = 118(页码),121357 % 1024 = 505(偏移量)。
对于 16479315,16479315 / 1024 = 16092(页码),16479315 % 1024 = 773(偏移量)。
对于 27253187,27253187 / 1024 = 26614(页码),27253187 % 1024 = 591(偏移量)。
第四题(存储管理_分页)
假设有一个系统具有 32 位的虚拟地址和 4KB 的页面。
编写一个程序,其命令行的输入参数为虚拟地址 (十进制), 其输出为对应的页码和偏移。
例如,你的程序可按如下的代码运行:
./addresses 19986
其输出为:
The address 19986 contains:
page number = 4
offset = 3602
ANS:
因为页大小为 ,所以偏移量占 位,页码占 位。
通过将输入的虚拟地址右移 12 位得到页码;
用虚拟地址与 0x00000FFF(12 位全 1,用于获取低 12 位)进行按位与操作得到偏移量。
以下是使用Python实现的程序:
python
import sys
def address_conversion(virtual_address):
page_size = 4096 # 4KB
page_number = virtual_address >> 12
offset = virtual_address & 0x00000FFF
print(f"The address {virtual_address} contains:")
print(f"page number = {page_number}")
print(f"offset = {offset}")
if __name__ == "__main__":
if len(sys.argv)!= 2: #sys.argv 用于获取命令行参数。
print("Usage: python program.py <virtual_address>")
sys.exit(1)
virtual_address = int(sys.argv[1])
#sys.argv[0] 是程序本身的名称(在你的例子中是 main.py)
#而 sys.argv[1] 就是期望用户传入的虚拟地址参数。
address_conversion(virtual_address)
第五题(存储管理_内存共享与保护)
什么是写时复制功能?在什么情况下它的使用时有效的?实现这种功能需要什么硬件支持?
ANS:
1.定义
写时复制是一种优化技术,当多个进程共享同一块内存页面时,它们最初都以只读方式访问该页面。如果某个进程试图对该页面进行写操作,操作系统会为该进程复制一份该页面的副本,然后让该进程在副本上进行写操作,而其他进程仍然共享原始的只读页面。
2.什么情况有效
在多进程共享大量相同数据且只有少数进程会修改数据的情况下使用有效,这样可以避免为每个进程都复制一份数据,节省内存空间。
3.硬件支持
实现这种功能需要硬件支持内存管理单元(MMU)来跟踪页面的访问权限和执行复制操作。
第六题(虚拟存储管理_请求调页)
假设有一个请求调页存储器。页表保存在寄存器中。
如果有可用空帧或者置换的页面未被修改,则缺页错误的处理需要 8ms, 如果置换的页面已被修改,则需要 20ms。
内存访问时间为 100ns。
假设需要置换的页面在 70% 的时间内会被修改。
对于有效访问时间不超过 200ns, 最大可接受的缺页错误率是多少?
ANS:
设缺页错误率为 。
有效访问时间 = (1 - p) * 内存访问时间 + p *(缺页处理时间 + 内存访问时间)。
当置换页面被修改时,缺页处理时间为 20ms;未被修改时为 8ms,平均缺页处理时间 = 0.7 * 20ms + 0.3 * 8ms = 16.4ms。
代入公式可得:200ns = (1 - p) * 100ns + p * (16.4ms + 100ns),然后解方程,
(约为 0.00061%)
所以最大可接受的缺页错误率约为 0.00061%。
第七题(虚拟存储管理_页面置换算法)
编写一个程序,实现本章节所描述的 FIFO、LRU 和最优页面置换算法。
首先,生成一个随机的页面引用串,其中页码范围为 0~9。将这个随机页面引用串应用到每个算法中,并记录每个算法引起的缺页错误的数量。在启动时将页帧数传递给程序。可以使用所选择的任何编程语言来实现此程序。
ANS:
FIFO 算法:先进先出算法,用队列模拟。新页面入队尾,缺页且队列满时,淘汰队首页面。
LRU 算法:最近最少使用算法,可用字典记录页面访问顺序。页面访问时更新字典,缺页时淘汰最久未使用页面(字典中最早的键)。
最优页面置换算法:置换未来最长时间不被访问的页面。需预先知道页面引用串全部信息,实际难实现,但可用于性能比较。分析引用串,选未来最长时间不被用的页面置换。
python
import random
def generate_page_reference_string(length):
return [random.randint(0, 9) for _ in range(length)]
def fifo(page_reference_string, frame_count):
frames = []
page_faults = 0
for page in page_reference_string:
if page not in frames:
if len(frames) == frame_count:
frames.pop(0)
frames.append(page)
page_faults += 1
return page_faults
def lru(page_reference_string, frame_count):
frames = {}
page_faults = 0
for i, page in enumerate(page_reference_string):
if page not in frames:
if len(frames) == frame_count:
oldest_page = min(frames, key=frames.get)
del frames[oldest_page]
frames[page] = i
page_faults += 1
else:
frames[page] = i
return page_faults
def optimal(page_reference_string, frame_count):
frames = []
page_faults = 0
for i, page in enumerate(page_reference_string):
if page not in frames:
if len(frames) == frame_count:
future_pages = page_reference_string[i + 1:]
farthest_page = max(frames, key=lambda p: future_pages.index(p) if p in future_pages else float('inf'))
frames.remove(farthest_page)
frames.append(page)
page_faults += 1
return page_faults
if __name__ == "__main__":
page_reference_string = generate_page_reference_string(20)
print("Page reference string:", page_reference_string)
frame_count = 3
print("FIFO page faults:", fifo(page_reference_string.copy(), frame_count))
print("LRU page faults:", lru(page_reference_string.copy(), frame_count))
print("Optimal page faults:", optimal(page_reference_string.copy(), frame_count))