基于顺序搜索的分区分配算法

为了实现动态分区分配,通常是将系统中的空闲分区链接成一个链。基于顺序搜索的分配方式是依次搜索空闲分区链上的空闲分区,去寻找一个其大小能满足要求的分区,主要有如下四种算法。

首次适应算法

首次适应(first fit,FF)算法要求空闲分区链以地址递增的次序链接,在分配内存时从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,内存分配失败。
image.png
该算法倾向于优先利用内存中低址部分的空闲分区,保留了高址部分的大空闲区。缺点是低址部分不断被划分,会留下许多难以利用的外部碎片。而每次查找又都是从低址部分开始的,会导致搜索的时间开销较大。

循环首次适应算法

为避免低址部分留下许多很小的空闲分区,以及减少查找可用空闲分区的开销,可以使用循环首次适应算法。循环首次适应(next fit,NF)算法在为进程分配内存空间时,是从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满足要求的空闲分区。实现该算法一般会使用循环链表,如果最后一个(链尾)空闲分区的大小仍不能满足要求,则应返回到第一个空闲分区。
image.png
算法能使内存中的空闲分区分布得更均匀,减少了查找空闲分区时的开销。但这样会导致高地址的大分区可能被划分为小分区来使用,使缺乏大的空闲分区给较大的进程。

最佳适应算法

最佳适应(best fit,BF)算法在每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业。该算法要求将所有的空闲分区按其容量以从小到大的顺序形成一空闲分区链,这样第一次找到的能满足要求的空闲区必然是最佳的。
image.png
由于每次分配后所切割下来的剩余部分总是最小的,所以在存储器中会留下许多难以利用的碎片。

最坏适应算法

最坏适应(worst fit,WF)算法在扫描整个空闲分区表或链表时,总是挑选一个最大的空闲区,从中分割一部分存储空间给作业使用。该算法要求将所有的空闲分区,按其容量以从大到小的顺序形成空闲分区链。
image.png
这个算法会使存储器中缺乏大的空闲分区,它的优点是可使剩下的空闲区不至于太小,产生碎片的可能性最小,对中、小作业有利。同时最坏适应分配算法查找效率很高,查找时只要看第一个分区能否满足作业要求即可。

实验说明

实验目的

理解动态异长存储分区资源管理,掌握所需数据结构和管理程序,了解各种存储分配算法的优点和缺点。

实验内容

按内容要求编写最佳适应和最坏适应存储分配算法。编写测试程序,对存储分配表进行初始化,然后对用户输入的请求和释放,按算法动态更新存储分配表,并将每次更新之后的存储分配表在屏幕上显示出来。

代码编写

ResourceTable 类

ResourceTable 类为系统资源表,有如下 3 个属性。

属性 数据类型 说明
FreeSpace list 空闲空间表
AllocatedSpace list 已分配空间表
method str 分配方式,bf 为最佳适应,wf 为最坏适应

ResourceTable 类有如下 5 个方法。

方法 说明
init (self, size) 构造 ResourceTable 对象
distributeSpace(self, size) 分配空间
releaseSpace(self, address) 释放空间
printFree(self) 打印空闲空间表的信息
printAllocated(self) 打印已分配空间表的信息
  1. class ResourceTable(object):
  2. def __init__(self, size):
  3. '''
  4. 构造一个 ResourceTable 对象,为系统资源表。
  5. param size: int,空间的总大小
  6. '''
  7. self.FreeSpace = [] #空闲空间表
  8. self.AllocatedSpace = [] #已分配空间表
  9. self.method = 'bf' #分配方式,bf为最佳适应,wf为最坏适应
  10. #初始化一个大小为size的空闲空间
  11. self.FreeSpace.append(Space(0,size))
  12. def distributeSpace(self, size):
  13. '''
  14. 分配空间,从空闲空间表划分一个空闲空间,加入到已分配空间表。
  15. param size: int,划分出的空间大小
  16. '''
  17. idx = -1
  18. for i in range(len(self.FreeSpace)):
  19. #由于空闲空间表按照分配算法的特点进行排序,
  20. #所以找到的第一个可分配空间即可结束搜索
  21. if self.FreeSpace[i].size >= size:
  22. idx = i
  23. break
  24. if idx == -1:
  25. #没有符合要求的空闲空间
  26. print("Error !")
  27. else:
  28. #划分一个新的空间
  29. space = Space(self.FreeSpace[i].address, size)
  30. self.AllocatedSpace.append(space)
  31. if self.FreeSpace[i].size - size == 0:
  32. #刚好划分整个空间
  33. self.FreeSpace.pop(i)
  34. else:
  35. #划分一部分需要的空间
  36. self.FreeSpace[i].address += size
  37. self.FreeSpace[i].size -= size
  38. if self.method == 'bf':
  39. #最佳适应算法,按空闲空间由小到大的顺序排序
  40. self.FreeSpace.sort(key = Space.getSize)
  41. else:
  42. #最坏适应算法,按空闲空间由大到小的顺序排序
  43. self.FreeSpace.sort(key = Space.getSize, reverse=True)
  44. #已分配空间表按地址顺序排序
  45. self.AllocatedSpace.sort(key = Space.getAddress)
  46. def releaseSpace(self, address):
  47. '''
  48. 释放空间,从已分配空间表释放一个空间,返回到空闲空间表,相邻的空间进行合并。
  49. param address: int,释放的空间地址
  50. '''
  51. idx = -1
  52. for i in range(len(self.AllocatedSpace)):
  53. #搜索是否有该地址的已分配空间
  54. if self.AllocatedSpace[i].address == address:
  55. idx = i
  56. break
  57. if idx == -1:
  58. #没有找到要释放的地址
  59. print("Error !")
  60. else:
  61. #释放空间,返回空闲空间表
  62. newSpace = self.AllocatedSpace.pop(idx)
  63. self.FreeSpace.append(newSpace)
  64. self.FreeSpace.sort(key = Space.getAddress)
  65. #相邻的空间进行合并
  66. flag = 1
  67. while flag:
  68. #由于在遍历时破坏被迭代的结构是危险的,所以采用多次合并的方法
  69. flag = 0
  70. for i in range(len(self.FreeSpace) - 1):
  71. if self.FreeSpace[i].address + self.FreeSpace[i].size == self.FreeSpace[i + 1].address:
  72. #如果表中2个空间可以合并,合并大小并设置被合并的空间为标志-1
  73. self.FreeSpace[i].size += self.FreeSpace[i + 1].size
  74. self.FreeSpace[i + 1].address = -1
  75. #由于被迭代对象结构的改变,所以需要再次合并
  76. flag = 1
  77. for space in self.FreeSpace:
  78. if space.address == -1:
  79. #删除被标记为-1的空间
  80. self.FreeSpace.remove(space)
  81. #已分配空间表只是取出了一个元素,所以其他元素还是有序的不需要排序
  82. if self.method == 'bf':
  83. #最佳适应算法,按空闲空间由小到大的顺序排序
  84. self.FreeSpace.sort(key = Space.getSize)
  85. else:
  86. #最坏适应算法,按空闲空间由大到小的顺序排序
  87. self.FreeSpace.sort(key = Space.getSize, reverse=True)
  88. def printFree(self):
  89. '''
  90. 打印空闲空间表的信息
  91. '''
  92. print("FreeSpace:")
  93. for space in self.FreeSpace:
  94. print(space)
  95. def printAllocated(self):
  96. '''
  97. 打印已分配空间表的信息
  98. '''
  99. print("AllocatedSpace:")
  100. for space in self.AllocatedSpace:
  101. print(space)

Space 类

Space 类用于刻画单个空间,有如下 2 个属性。

属性 数据类型 说明
address int 起始地址
size int 空间大小

Space 类有如下 4 个方法。

方法 说明
init (self, address, size) 构造 Space 对象
str 重写魔术方法
releaseSpace(self, address) 释放空间
getSize(self) 获取 address 属性的 get 方法,排序用
getAddress(self) 获取 size 属性的 get 方法,排序用
  1. class Space(object):
  2. def __init__(self, address, size):
  3. '''
  4. 构造一个 Space 对象,表示单个空间。
  5. param address: int,空间的起始地址
  6. param size: int,空间的总大小
  7. '''
  8. self.address = address #起始地址
  9. self.size = size #空间大小
  10. def __str__(self):
  11. '''
  12. 魔术方法,格式化输出Space对象。
  13. '''
  14. return ("address: {}; size: {}".format(self.address, self.size))
  15. def getSize(self):
  16. '''
  17. 获取address属性的get方法,排序用。
  18. '''
  19. return self.size
  20. def getAddress(self):
  21. '''
  22. 获取size属性的get方法,排序用。
  23. '''
  24. return self.address

测试代码

  1. #测试代码
  2. size = int(input("请输入空闲空间的总大小:"))
  3. table = ResourceTable(size)
  4. method = input("请输入分配方式:")
  5. if method == 'wf':
  6. table.method = 'wf'
  7. while 1:
  8. action = int(input("请输入你的动作,1为申请,2为释放:"))
  9. if action == 1:
  10. size = int(input("请输入申请空间的大小:"))
  11. table.distributeSpace(size)
  12. elif action == 2:
  13. address = int(input("请输入释放的地址:"))
  14. table.releaseSpace(address)
  15. else:
  16. break
  17. table.printFree()
  18. table.printAllocated()

运行效果

最佳适应算法

image.png
image.png

最坏适应算法

image.png
image.png
image.png