1. 程式人生 > >記憶體碎片及夥伴演算法

記憶體碎片及夥伴演算法

今天學習到 Linux 記憶體分配問題,有些不明白,什麼是記憶體碎片問題?以及為什麼maloc()等函式每次分配記憶體後都會用 free()釋放資源,為什麼還會產生碎片問題?記憶體碎片問題如何產生 及 如何解決呢?
以下是自己今天學習心得:
記憶體碎片概念:
記憶體碎片問題分為內部碎片和外部碎片兩種。
   1.內部碎片是由於採用固定大小的記憶體分割槽,當一個程序不能完全使用分給它的固定記憶體區域時,就將該程序分配後剩餘的部分稱為內碎片。通常內碎片難以避免;
   2.外部碎片是由於某些未分配的連續區域太小,不足以為任意程序分配記憶體資源的記憶體塊大小,此時稱這些不可用的記憶體塊大小為外部碎片


對於malloc()等函式,每次申請完記憶體後都會釋放,但每次釋放的記憶體大小及釋放時間的不同就會產生記憶體碎片。比如:在記憶體單元100的起始地址到記憶體單元200之間,共申請了100個1位元組的空間。在free()時,釋放了記憶體地址為奇數的記憶體單元(如101,103,105……)而偶數單元不釋放,釋放了50個1位元組空間,雖然總空間數為50位元組,但由於這50個1位元組空間不連續。當下次要申請2位元組的記憶體單元時,卻無法在100到200的記憶體地址單元中申請到空間,於是就產生記憶體碎片問題。


為什麼會產生記憶體碎片?
對於記憶體的分配方法有:連續地址分配、分頁機制和分段機制以及段頁式(網上有很多關於記憶體地址分配的文章,都很不錯,可以瞭解一下)
連續地址分配:固定分割槽分配會產生內碎片問題,動態分割槽分配會產生外碎片問題

分頁機制:相比較固定分配分割槽,內碎片問題已經明顯減少

分段機制:消除內碎片問題,但會產生外碎片問題

夥伴演算法可以解決外碎片問題,其演算法思想如下:

無論已經分配的分割槽還是空閒分割槽,其大小均為2的k次冪,k為整數,1<=k<=m,其中2^1表示分配的最小分割槽大小,2^m 表示分配的最大分割槽的大小。在系統開始執行時,整個記憶體區是一個大小為2^m的空閒分割槽,隨著系統執行,空閒區的不斷劃分會形成若干不連續的空閒分割槽,將這些空閒分割槽按照分割槽的大小進行分類,對於每一類具有相同大小的所有空閒分割槽,單獨成立一個空閒分割槽雙向連結串列。這樣,不同大小的空閒分割槽就形成了k(0<=k<=m)個空閒分割槽連結串列。

當需要為程序分配一個長度為n 的儲存空間時,首先計算i 的值,使2^(i-1)< n < 2^ i ,然後在空閒分割槽大小為i 的空閒區連結串列中查詢。若找到,則把該空閒分割槽分配給該程序。否則,表明長度為2^ i 的空閒分割槽已經耗盡,則在長度為2^(i+1)的空閒分割槽連結串列中查詢。若存在大小為2^(i+1)的空閒分割槽,則將該分割槽分為連個大小均為2^ i 的塊,一個塊分配給該程序,一個塊掛載在長度大小為2^ i 的空閒分割槽連結串列中。若大小為2^(i+1)的空閒分割槽也已經耗盡,則尋找大小為2^(i+2)的空閒分割槽,若找到,則對該分割槽進行兩次劃分,第一次劃分,將大小為2^(i+2)的分割槽分為兩個大小為2^(i+1)的空閒分割槽,一個掛載在大小為2^(i+1)的空閒分割槽上,一個再次分割為兩個大小為2^ i 的分割槽,一個掛載在大小為2^ i 的空閒分割槽上,一個用於分配給該程序;如果未找到大小為2^ ( i+2 ) 的空閒分割槽,則在2^( i+3) 的空閒分割槽上尋找,一次重複以上步驟,指導找到空閒區

在Linux中將這記憶體分為10個空閒分割槽連結串列,0-9,大小範圍是:2^0 - 2^9


以上過程的逆過程就是夥伴演算法的釋放過程,釋放過程需要滿足兩個條件:1.兩個塊具有相同的大小  2.它們的實體地址是連續的

也正是基於以上兩個條件才稱該演算法為夥伴演算法

Linux夥伴演算法中涉及到的資料結構:

free_area_t    free_area[MAX_ORDER];

我們再次對free_area_t  給予較詳細的描述。

#difine   MAX_ORDER  10

type struct free_area_struct {

           struct list_head   free_list

                 unsigned  int    *map

 } free_area_t


其中list_head域是一個通用的雙向連結串列結構,連結串列中元素的型別將為mem_map_t(struct page結構)Map域指向一個位圖,其大小取決於現有的頁面數。free_areak項點陣圖的每一位,描述的就是大小為2k頁面的兩個夥伴塊的狀態。如果點陣圖的某位為0,表示一對兄弟塊中或者兩個都空閒,或者兩個都被分配,如果為1,肯定有一塊已被分配。當兄弟塊都空閒時,核心把它們當作一個大小為2k+1的單獨快來處理