資料結構隨筆—動態儲存管理
動態儲存管理的基本問題是如何應使用者請求分配記憶體,如何回收那些使用者不在使用而釋放的記憶體。
經過一段時間的執行,有些使用者執行結束,它所佔用的記憶體區變成空閒塊,只就使整個記憶體區呈現出佔用快和空閒塊交錯的狀態,假如此時又有新的使用者進入系統請求分配記憶體,這時通常有兩種做法:
(1)、繼續從高地址的空閒塊中進行分配,直到分配無法進行,系統才去回收所有使用者不再使用的空閒塊,並且重新組織記憶體,將所有空閒的記憶體塊連線在一起成為一個大的空閒塊。
(2)、使用者一旦執行結束,便將它所佔用的記憶體塊釋放成空閒塊。當有新使用者請求分配記憶體時,系統巡視整個記憶體區中所有的記憶體塊,並從中找出一個合適的空閒塊分配。
可利用空間表及分配方法
可利用空間表有下列3種不同的結構形式:
(1)、系統執行期間所有使用者請求分配的儲存量的大小相同;每個記憶體塊的大小相同。
(2)、系統執行期間使用者請求分配的儲存量有若干種大小的規格;建立若干個可利用空間表,同一連結串列中的結點大小相同。並增加一個標誌位tag,表示是空閒還是佔用。當請求的記憶體塊過大時,執行儲存緊縮操作。
(3)、系統在執行期間分配給使用者的記憶體塊大小不固定,可以隨請求而變化。所以可利用的空間表只有一個大小為整個記憶體區的結點。
分配策略:
(1)首次擬合法:從表頭指標開始查詢可利用空間表,將找到的第一個大小不小於n的空閒塊的一部分分配給使用者。
(2)最佳擬合法:將可利用空間表中一個不小於n且最接近n的空閒塊的一部分分配給使用者。所以可利用空間表應該從小到大排序
(3)最差擬合法:將可利用空間表中不小於n且是連結串列中最大的空閒塊的一部分分配給使用者。所以可利用空間表可以從大到小排序。
邊界標識法:
在每個記憶體區的頭部和底部兩個邊界上分別設有標識,以標識給區域為佔用快或者空閒塊,以便將所有地址連續的空閒儲存區組成一個儘可能大的空閒塊。
頭部有4個區域:llink指向前驅結點,tag標識空閒或者佔用,size表示大小,rlink指向後驅結點。
尾部有2個區域:uplink底部閾,本節點的低指標。tag標識空閒或者佔用。
分配演算法:
假設首次擬合法,邊界標識法還有如下兩條約定:
1、首次擬合會出現有很多容量極小總也分配不出去的空閒塊,這就大大減慢了分配的速度(查詢)的。彌補的辦法是:選定一個適當的常量e,當容量m-請求量n<e時,就將容量m的空閒塊整塊分配給使用者。
2、如果每次分配都是從同一個結點開始查詢,會造成儲存量小的結點密集在頭指標附近這同樣會增加查詢較大空閒塊的時間。所以避免的方法是在每次分配之後,令指標pav指向剛進行過分配的結點的後繼結點。
回收演算法:
1、如果釋放塊的左右鄰區都是佔用塊。此時簡單插入即可。
2、如果釋放塊的作用鄰區有一個是空閒塊。
3、左右鄰區都是空閒塊。
夥伴系統:
在夥伴系統中,無論是佔用塊或空閒塊,其大小均是2的k次冪。
分配演算法:
在可利用表上尋找結點大小與n相匹配的子表,若非空,則直接分配,若空,則到更大的非空子表中去查詢,知道找到一個空閒塊,將剩餘部分插入到相應的子表。
回收演算法:
夥伴:在分配時經常需要將一個大的空閒塊分裂成兩個大小相等的儲存區,這兩個由同一大塊分裂出來的小塊就稱之為互為夥伴。
在回收空閒塊時,應首先判別其夥伴是否為空閒塊,若否,則只要將釋放的空閒塊插入到相應的子表即可。若是,則需要在相應子表中找到其夥伴並刪除之,然後在判別合併後的夥伴是否是空閒塊。以此重複,知道歸併到所得空閒塊的夥伴不是空閒塊時,在插入到相應的子表中去。
無用單元收集:
無用單元和懸掛訪問:解決途徑:
(1)使用訪問計數器:在子表或者廣義表中增加一個表頭結點。他的值是指向該子表或者廣義表的指標數目;當為零時,釋放結點‘
(2)當可用表為空是才回收,將不被使用的結點連結在一起,成為一個新的可利用空間表,而後程式在繼續執行。
儲存緊縮:在堆的動態儲存管理方法中,可利用空間不管什麼時候都是一個連續的儲存區。從低到高依次分配。當回收空閒塊合併到堆上去的時候稱為儲存緊縮。
有兩種方式:
(1)一旦有使用者釋放儲存塊即進行回收緊縮。
(2)在程式執行過程中不回收,直到可利用空間不夠的時候或者堆指標指向最高地址時才進行儲存緊縮。將所有空閒塊練成一片即將佔用塊都集中到低地址區,而剩餘的高地址區成為一個連續地址的空閒塊。
還需要以下4步:
1、計算佔用塊的新地址。
2、修改使用者的初始變量表。
3、檢查每個佔用塊中儲存的資料。
4、將所有佔用塊遷移到新地址去。