記憶體管理演算法--Buddy夥伴演算法【轉】

來源:互聯網
上載者:User

標籤:記憶體管理   .net   div   去掉   freelist   根據   結構   mem   返回   

轉自:http://blog.csdn.net/orange_os/article/details/7392986

Buddy演算法的優缺點:

1)儘管夥伴記憶體演算法在記憶體片段問題上已經做的相當出色,但是該演算法中,一個很小的塊往往會阻礙一個大塊的合并,一個系統中,對記憶體塊的分配,大小是隨機的,一片記憶體中僅一個小的記憶體塊沒有釋放,旁邊兩個大的就不能合并。

2)演算法中有一定的浪費現象,夥伴演算法是按2的冪次方大小進行分配記憶體塊,當然這樣做是有原因的,即為了避免把大的記憶體塊拆的太碎,更重要的是使分配和釋放過程迅速。但是他也帶來了不利的一面,如果所需記憶體大小不是2的冪次方,就會有部分頁面浪費。有時還很嚴重。比如原來是1024個塊,申請了16個塊,再申請600個塊就申請不到了,因為已經被分割了。

3)另外拆分和合并涉及到 較多的鏈表和位元影像操作,開銷還是比較大的。

Buddy(夥伴的定義):

這裡給出夥伴的概念,滿足以下三個條件的稱為夥伴:
1)兩個塊大小相同;
2)兩個塊地址連續;
3)兩個塊必須是同一個大塊中分離出來的;

Buddy演算法的分配原理:

假如系統需要4(2*2)個頁面大小的記憶體塊,該演算法就到free_area[2]中尋找,如果鏈表中有空閑塊,就直接從中摘下並分配出去。如果沒有,演算法將順著數組向上尋找free_area[3],如果free_area[3]中有空閑塊,則將其從鏈表中摘下,分成等大小的兩部分,前四個頁面作為一個塊插入free_area[2],後4個頁面分配出去,free_area[3]中也沒有,就再向上尋找,如果free_area[4]中有,就將這16(2*2*2*2)個頁面等分成兩份,前一半掛如free_area[3]的鏈表頭部,後一半的8個頁等分成兩等分,前一半掛free_area[2]
的鏈表中,後一半分配出去。假如free_area[4]也沒有,則重複上面的過程,知道到達free_area數組的最後,如果還沒有則放棄分配。


 

Buddy演算法的釋放原理:

記憶體的釋放是分配的逆過程,也可以看作是夥伴的合并過程。當釋放一個塊時,先在其對應的鏈表中考查是否有夥伴存在,如果沒有夥伴塊,就直接把要釋放的塊掛入鏈表頭;如果有,則從鏈表中摘下夥伴,合并成一個大塊,然後繼續考察合并後的塊在更大一級鏈表中是否有夥伴存在,直到不能合并或者已經合并到了最大的塊(2*2*2*2*2*2*2*2*2個頁面)。


整個過程中,位元影像扮演了重要的角色,2所示,位元影像的某一位對應兩個互為夥伴的塊,為1表示其中一塊已經分配出去了,為0表示兩塊都空閑。夥伴中無論是分配還是釋放都只是相對的位元影像進行異或操作。分配記憶體時對位元影像的
是為釋放過程服務,釋放過程根據位元影像判斷夥伴是否存在,如果對相應位的異或操作得1,則沒有夥伴可以合并,如果異或操作得0,就進行合并,並且繼續按這種方式合并夥伴,直到不能合并為止。


Buddy記憶體管理的實現:

提到buddy 就會想起linux 下的實體記憶體的管理 ,這裡的memory pool 上實現的 buddy 系統

和linux 上按page 實現的buddy系統有所不同的是,他是按照位元組的2的n次方來做block的size

實現的機制中主要的結構如下:

整個buddy 系統的結構:

struct mem_pool_table

{

#define MEM_POOL_TABLE_INIT_COOKIE (0x62756479)

uint32 initialized_cookie; /* Cookie 指示記憶體已經被初始化後的魔數,  如果已經初始化設定為0x62756479*/

uint8 *mem_pool_ptr;/* 指向記憶體池的地址*/

uint32 mem_pool_size; /* 整個pool 的size,下面是整個max block size 的大小*/

uint32 max_block_size; /* 必須是2的n次方,表示池中最大塊的大小*/   
boolean assert_on_empty; /* 如果該值被設定成TRUE,記憶體配置請求沒有完成就返回 並輸出出錯資訊*/
 uint32 mem_remaining; /* 當前記憶體池中剩餘記憶體位元組數*/                                              
uint32 max_free_list_index; /* 最大freelist 的下標,*/
struct mem_free_hdr_type     *free_lists[MAX_LEVELS];/* 這個就是夥伴系統的level數組*/

#ifdef FEATURE_MEM_CHECK
uint32 max_block_requested;
  uint32 min_free_mem; /* 放mem_remaining */
#endif /* FEATURE_ONCRPC_MEM_CHECK*/
};

 

這個結構是包含在free node 或alloc node 中的結構:

其中check 和 fill 都被設定為某個pattern
用來檢查該node 的合法性
#define MEM_HDR_CHECK_PATTERN ((uint16)0x3CA4)
#define MEM_HDR_FILL_PATTERN ((uint8)0x5C)


typedef struct  tagBuddyMemBlockHeadType

{

    mem_pool_type pool; /*回指向記憶體池*/

    uint16 check;

    uint8 state; /* bits 0-3 放該node 屬於那1級 bit 7 如果置1,表示已經分配(not free)

    uint8 fill;

} BUDDY_MEM_BLOCK_HEAD_TYPE;


這個結構就是包含node 類型結構的 free header 的結構:

typedef struct  tagBuddyMemHeadType

{

    mem_node_hdr_type hdr;

    struct mem_free_hdr_type * pNext;   /* next,prev,用於串連free header的雙向 list*/

    struct mem_free_hdr_type * pPrev;

} mem_free_hdr_type;

這個結構就是包含node 類型結構的 alloc header 的結構:
已指派的mem 的node 在記憶體中就是這樣表示的

  1. typedef struct mem_alloc_hdr_type
  2. {
  3.    mem_node_hdr_type hdr;

  4. #ifdef FEATURE_MEM_CHECK_OVERWRITE
  5.    uint32     in_use_size;
  6. #endif

  7. } mem_alloc_hdr_type;

其中用in_use_size 來表示如果請求分配的size 所屬的level上實際用了多少
比如申請size=2000bytes, 按size to level 應該是2048,實際in_use_size
為2000,剩下48byte 全部填充為某一數值,然後在以後free 是可以check
是否有overwite 到著48byte 中的數值,一般為了速度,只 檢查8到16byte

另外為什麼不把這剩下的48byte 放到freelist 中其他level 中呢,這個可能
因為本來buddy 系統的缺點就是容易產生片段,這樣的話就更碎了

關於free or alloc node 的:

假設

最小塊為2^4=16,著是由mem_alloc_hdr_type (12byte)決定的, 實際可分配4byte

如果假定最大max_block_size =1024,

如果pool 有mem_free_hdr_type[0]上掛了兩個1024的block node

是free node, 紫色為alloc node


接下來主要是buddy 系統的操作主要包括pool init , mem alloc ,mem free

pool init :
 1. 將實際pool 的大小去掉mem_pool_table 結構大小後的size 放到
     mem_pool_size, 並且修改實際mem_pool_ptr指向前進mem_pool_table
     結構大小的地址
 2.  接下來主要將mem_pool_size 大小的記憶體,按最大塊掛到free_lists 上
    level 為0的list 上,然後小於該level block size 部分,繼續掛大下一
    級,迴圈到全部處理完成  (感覺實際用於pool的size ,應該為減去
    mem_pool_table 的大小,然後和最大塊的size 對齊,這樣比較好,
    但沒有實際測試過)
   
   
mem alloc:
    這部分相當簡單,先根據請求mem的size ,實際分配時需要加上mem_alloc_hdr_type
這12byte ,然後根據調整後的size,計算實際應該在那個 level上分配,如果有相應級
很簡單,直接返回,如果沒有,一級一級迴圈尋找,找到後,把省下的部分,在往下一級
一級插入到對應級的freelist 上

mem free:
     其中free 的地址,減去12 就可以獲得mem_alloc_hdr_type 結構
     然後確定buddy 在該被free block 前,還是後面, 然後合并buddy,
     迴圈尋找上一級的buddy ,有就再合并,只到最大block size 那級



關於這個演算法,在<<The Art  of Computer Programming>> vol 1,的
動態儲存裝置分配中有描述,對於那些只有OSAL 的小系統,該演算法相當有用

記憶體管理演算法--Buddy夥伴演算法【轉】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.