解析內存管理的方式
正文
說到內存分配,我們立刻就會想到malloc()、calloc()等申請內存的接口,說到內存分配的算法,我們會想到Buddy和Slab等分配算法。那麼你有沒有思考過,申請的內存是如何管理的呢?管理的方式都有哪些?這就是本文將要討論的。
本文將介紹兩種內存管理的方法:鏈表法和比特位法。
第零節 問題初始化
假設現有一坨大小為M的內存,我們將它分為N塊,那麼每塊的大小就是BLOCK_SIZE = M/N,如下圖所示:
第一節 鏈表法
所謂鏈表法內存管理,就是說將已經分好的一坨內存分成了許多的小塊,然後將每個小塊以鏈表的形式串起來。如下圖:
從圖中可看到,我們在每個小塊中添加了名為link的鏈表節點,它表示為:
[cpp]
struct list_head
{
struct list_head *next, *prev;
};
附注:在內核中該鏈表為雙向鏈表,不過在上圖中為了簡潔,我將其表示為單鏈表。
於是,我們就可以用一個名為head的頭結點將這些小塊串聯起來了。當我們使用時,只需從鏈表上摘一個即可,用完之後就可還回。利用鏈表來管理內存的優點有以下兩點:
1. 即用即拿,用完即還(方便快捷):就是說當我們需要在這坨申請好的內存中使用一個或者幾個小塊時,我們就可根據需要,從鏈表上摘下來一個或者幾個,用完之後直接還回鏈表中即可。
2. 管理流與數據流的融合與分離(節省空間):當我們利用鏈表法管理內存時,我們只需知道每個塊的link,這樣我們就能利用link來管理每個塊,我們說它們是融合的;當你要使用某個塊時,將其從鏈表中摘下來,這個時候我們就用這個塊來進行數據流操作,對於link我們並不關心,在這個角度上我們說它們是分離的。不論融合與分離,我們在操作時並沒有用到額外的空間,而是在每個塊的內部解決了管理流與數據流。
好了,這就是鏈表法內存管理。節末,我還是給出鏈表法的代碼:
[cpp]
/**
* 鏈表法內存管理:內存初始化
* addr: 表示塊的起始地址
* block_size: 表示每個塊的大小
* block_number: 表示塊的個數
*/
void MemoryInit(void* addr, unsigned long block_size, unsigned int block_number)
{
int i = 0;
struct list_head *link = (struct list_head*)addr;
for(; i < block_number; i++)
{
list_add_tail(link, head);//添加到鏈表尾部
addr += block_size;
link = (struct list_head*)addr;
}
}
[cpp]
/**
* 鏈表法內存管理:內存塊分配
*/
void* alloc_blkmem(void)
{
struct list_head *link = NULL;
if(!list_empty(head))//鏈表不為空
{
link = head->next;
list_del_init(link);//從鏈表中摘除
}
return link;
}
[cpp]
/**
* 鏈表法內存管理:內存塊釋放
*
* addr: 表示塊的起始地址
*/
void free_blkmem(void* addr)
{
struct list_head *link = (struct list_head*)addr;
list_add_tail(link, head);//還回到鏈表中
}
第二節 比特位法
和鏈表法相比,比特位法就更簡單了。比特位的思想很簡單,就是說當某個塊沒有被使用時,我們讓該塊對應位置的bit位為0,當這個塊被使用時,就將它的bit位置為1。如下圖:
比特位法的確很直觀,這是它的優點,但是和鏈表法相比,它在時間和空間上都不及鏈表法。我們來看看:
在時間上:鏈表法是即用即拿,而比特位法則不然,它必須對bit表進行遍歷,當bit位為0時方可取用;
在空間上:鏈表法不需額外的空間,而比特位法則取額外的空間來存儲bitmap表,有一個塊就得對應一個bit位,當數據塊很多時,這也是一筆不消的開銷。
雖然比特位法在時間上和空間上都不是很理想,但是它很直觀,易理解。它也很常用!
好了,比特位法就是個這,因為它很直觀,所以我用很簡單的幾句話就說完了。節末,還是老辦法,給出比特位法的代碼,縱然它很簡單!
[cpp]
/** 設置bitmap的指定位
*
* src: 表示bitmap
* index:表示指定位
*/
void bitmap_set_bit(void *src, unsigned int index)
{
unsigned short* data_bitmap = (unsigned short *)src;
data_bitmap[index] |= 1 << index;
} www.2cto.com
[cpp]
/** 清除bitmap的指定位
*
* src: 表示bitmap
* index:表示指定位
*/
void bitmap_clear_bit(void *src, unsigned int index)
{
unsigned short* data_bitmap = (unsigned short *)src;
data_bitmap[index] &= ~(1 << index);
}
第三節 結束語
想想、寫寫、畫畫......