日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

内存管理算法--Buddy伙伴算法

發布時間:2024/9/30 编程问答 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 内存管理算法--Buddy伙伴算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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

采用buddy算法,解決了外碎片問題,這種方法適合大塊內存請求,這是因為把頁作為單位內存塊,不適合小內存區請求。如:幾十個或者幾百個字節。

對于小內存的請求,slab算法可能更好的解決內碎片問題。

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 在內存中就是這樣表示的
  • typedef struct mem_alloc_hdr_type
  • {
  • ???mem_node_hdr_type hdr;

  • #ifdef FEATURE_MEM_CHECK_OVERWRITE
  • ???uint32???? in_use_size;
  • #endif

  • }?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算法的實現,但是只是toy,總內存大小不能動態調整

    http://coolshell.cn/articles/10427.html

    buddy2_new只是申請了一塊小內存,用于管理大內存的分配,設這塊大內存的起始地址是realstart.對于buddy2而言,是按照page管理大內存的。

    對于buddy2_alloc返回的偏移是offset, 而實際的內存偏移應該是 realstart+offset*pageSize


    總結

    以上是生活随笔為你收集整理的内存管理算法--Buddy伙伴算法的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。