基於順序搜索的分區分配算法
為了實現動態分區分配,通常是將系統中的空閑分區鏈接成一個鏈。基於順序搜索的分配方式是依次搜索空閑分區鏈上的空閑分區,去尋找一個其大小能滿足要求的分區,主要有如下四種算法。
首次適應算法
首次適應(first fit,FF)算法要求空閑分區鏈以地址遞增的次序鏈接,在分配內存時從鏈首開始順序查找,直至找到一個大小能滿足要求的空閑分區為止。然后再按照作業的大小,從該分區中划出一塊內存空間,分配給請求者,余下的空閑分區仍留在空閑鏈中。若從鏈首直至鏈尾都不能找到一個能滿足要求的分區,則表明系統中已沒有足夠大的內存分配給該進程,內存分配失敗。
該算法傾向於優先利用內存中低址部分的空閑分區,保留了高址部分的大空閑區。缺點是低址部分不斷被划分,會留下許多難以利用的外部碎片。而每次查找又都是從低址部分開始的,會導致搜索的時間開銷較大。
循環首次適應算法
為避免低址部分留下許多很小的空閑分區,以及減少查找可用空閑分區的開銷,可以使用循環首次適應算法。循環首次適應(next fit,NF)算法在為進程分配內存空間時,是從上次找到的空閑分區的下一個空閑分區開始查找,直至找到一個能滿足要求的空閑分區。實現該算法一般會使用循環鏈表,如果最后一個(鏈尾)空閑分區的大小仍不能滿足要求,則應返回到第一個空閑分區。
算法能使內存中的空閑分區分布得更均勻,減少了查找空閑分區時的開銷。但這樣會導致高地址的大分區可能被划分為小分區來使用,使缺乏大的空閑分區給較大的進程。
最佳適應算法
最佳適應(best fit,BF)算法在每次為作業分配內存時,總是把能滿足要求、又是最小的空閑分區分配給作業。該算法要求將所有的空閑分區按其容量以從小到大的順序形成一空閑分區鏈,這樣第一次找到的能滿足要求的空閑區必然是最佳的。
由於每次分配后所切割下來的剩余部分總是最小的,所以在存儲器中會留下許多難以利用的碎片。
最壞適應算法
最壞適應(worst fit,WF)算法在掃描整個空閑分區表或鏈表時,總是挑選一個最大的空閑區,從中分割一部分存儲空間給作業使用。該算法要求將所有的空閑分區,按其容量以從大到小的順序形成空閑分區鏈。
這個算法會使存儲器中缺乏大的空閑分區,它的優點是可使剩下的空閑區不至於太小,產生碎片的可能性最小,對中、小作業有利。同時最壞適應分配算法查找效率很高,查找時只要看第一個分區能否滿足作業要求即可。
實驗說明
實驗目的
理解動態異長存儲分區資源管理,掌握所需數據結構和管理程序,了解各種存儲分配算法的優點和缺點。
實驗內容
按內容要求編寫最佳適應和最壞適應存儲分配算法。編寫測試程序,對存儲分配表進行初始化,然后對用戶輸入的請求和釋放,按算法動態更新存儲分配表,並將每次更新之后的存儲分配表在屏幕上顯示出來。
代碼編寫
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) | 打印已分配空間表的信息 |
class ResourceTable(object):
def __init__(self, size):
'''
構造一個 ResourceTable 對象,為系統資源表。
param size: int,空間的總大小
'''
self.FreeSpace = [] #空閑空間表
self.AllocatedSpace = [] #已分配空間表
self.method = 'bf' #分配方式,bf為最佳適應,wf為最壞適應
#初始化一個大小為size的空閑空間
self.FreeSpace.append(Space(0,size))
def distributeSpace(self, size):
'''
分配空間,從空閑空間表划分一個空閑空間,加入到已分配空間表。
param size: int,划分出的空間大小
'''
idx = -1
for i in range(len(self.FreeSpace)):
#由於空閑空間表按照分配算法的特點進行排序,
#所以找到的第一個可分配空間即可結束搜索
if self.FreeSpace[i].size >= size:
idx = i
break
if idx == -1:
#沒有符合要求的空閑空間
print("Error !")
else:
#划分一個新的空間
space = Space(self.FreeSpace[i].address, size)
self.AllocatedSpace.append(space)
if self.FreeSpace[i].size - size == 0:
#剛好划分整個空間
self.FreeSpace.pop(i)
else:
#划分一部分需要的空間
self.FreeSpace[i].address += size
self.FreeSpace[i].size -= size
if self.method == 'bf':
#最佳適應算法,按空閑空間由小到大的順序排序
self.FreeSpace.sort(key = Space.getSize)
else:
#最壞適應算法,按空閑空間由大到小的順序排序
self.FreeSpace.sort(key = Space.getSize, reverse=True)
#已分配空間表按地址順序排序
self.AllocatedSpace.sort(key = Space.getAddress)
def releaseSpace(self, address):
'''
釋放空間,從已分配空間表釋放一個空間,返回到空閑空間表,相鄰的空間進行合並。
param address: int,釋放的空間地址
'''
idx = -1
for i in range(len(self.AllocatedSpace)):
#搜索是否有該地址的已分配空間
if self.AllocatedSpace[i].address == address:
idx = i
break
if idx == -1:
#沒有找到要釋放的地址
print("Error !")
else:
#釋放空間,返回空閑空間表
newSpace = self.AllocatedSpace.pop(idx)
self.FreeSpace.append(newSpace)
self.FreeSpace.sort(key = Space.getAddress)
#相鄰的空間進行合並
flag = 1
while flag:
#由於在遍歷時破壞被迭代的結構是危險的,所以采用多次合並的方法
flag = 0
for i in range(len(self.FreeSpace) - 1):
if self.FreeSpace[i].address + self.FreeSpace[i].size == self.FreeSpace[i + 1].address:
#如果表中2個空間可以合並,合並大小並設置被合並的空間為標志-1
self.FreeSpace[i].size += self.FreeSpace[i + 1].size
self.FreeSpace[i + 1].address = -1
#由於被迭代對象結構的改變,所以需要再次合並
flag = 1
for space in self.FreeSpace:
if space.address == -1:
#刪除被標記為-1的空間
self.FreeSpace.remove(space)
#已分配空間表只是取出了一個元素,所以其他元素還是有序的不需要排序
if self.method == 'bf':
#最佳適應算法,按空閑空間由小到大的順序排序
self.FreeSpace.sort(key = Space.getSize)
else:
#最壞適應算法,按空閑空間由大到小的順序排序
self.FreeSpace.sort(key = Space.getSize, reverse=True)
def printFree(self):
'''
打印空閑空間表的信息
'''
print("FreeSpace:")
for space in self.FreeSpace:
print(space)
def printAllocated(self):
'''
打印已分配空間表的信息
'''
print("AllocatedSpace:")
for space in self.AllocatedSpace:
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 方法,排序用 |
class Space(object):
def __init__(self, address, size):
'''
構造一個 Space 對象,表示單個空間。
param address: int,空間的起始地址
param size: int,空間的總大小
'''
self.address = address #起始地址
self.size = size #空間大小
def __str__(self):
'''
魔術方法,格式化輸出Space對象。
'''
return ("address: {}; size: {}".format(self.address, self.size))
def getSize(self):
'''
獲取address屬性的get方法,排序用。
'''
return self.size
def getAddress(self):
'''
獲取size屬性的get方法,排序用。
'''
return self.address
測試代碼
#測試代碼
size = int(input("請輸入空閑空間的總大小:"))
table = ResourceTable(size)
method = input("請輸入分配方式:")
if method == 'wf':
table.method = 'wf'
while 1:
action = int(input("請輸入你的動作,1為申請,2為釋放:"))
if action == 1:
size = int(input("請輸入申請空間的大小:"))
table.distributeSpace(size)
elif action == 2:
address = int(input("請輸入釋放的地址:"))
table.releaseSpace(address)
else:
break
table.printFree()
table.printAllocated()
運行效果
最佳適應算法
最壞適應算法