struct head_fix;
這個頭不會返回給上層應用,是給釋放記憶體使用的.因為記憶體的請求是對齊到4位元組的,小於1024位元組的請求,被分成256個分配大小,分別是4,
8,12,....1024.每個大小的請求由乙個fix_obj_pool處理.idx的作用就是記錄是由哪個fix_obj_pool分配的記憶體.還有一點要注意的是,head_fix
本身占用了4個位元組,所以fix_obj_pool分配的物件大小實際是請求大小對齊到4倍數的大小再加上4.例如如果分配1個位元組,對齊到4就是4位元組,
所以實際分配記憶體的大小是8,只有後面4個位元組會返回給上層應用.
這種空間的浪費對於小的記憶體請求有點過分了,所以在實際使用中,這個所謂的通用記憶體分配器,其實不是為編譯時就已經可以確定大小的物件
使用的,對於編譯期就確定大小的物件,應該直接使用fix_obj_pool.只有那些在執行時才確定大小的記憶體分配請求,例如字串,變長結構等
才應該使用通用記憶體分配器.
下面介紹chunk_idx的作用.
首先回顧fix_obj_pool的實現,乙個chunk中的所有物件在位址上都是連續的,當chunk的空間不夠時,會再分配乙個chunk,然後將這些chunk按期首地
址大小的公升序排序.這樣,釋放乙個物件時,可以根據物件位址使用2分查詢快速的找到物件歸屬的chunk.
雖然2分查詢效率是比較高的,但最好還是能避免.在單獨使用fix_obj_pool的情況小,一般可以大致估算到系統中最大可能會分配多少個這類物件.
在建立fix_obj_pool時,傳入這個估算值,就可以生成乙個大小基本符合要求的chunk,這樣幾乎在大多數情況下都避免了釋放記憶體時的一次2分查詢.
但對於通用記憶體分配器,我們不太好估計這個值,所以,chunk的初始大小一般都不會設得太大.為了避免二分查詢,在分配分時,通過呼叫:
void *pool_alloc2(struct fix_obj_pool *pool,unsigned short *chunk_idx)
把chunk的下標一併返回,釋放時直接把這個下標傳進去就可以定位到正確的chunk了.
下面是通用記憶體分配器的**:
mem_allocator.h
#ifndef _mem_allocator_h#define _mem_allocator_h
struct allocator;
/** max:可以分配的最大請求位元組數
*/struct allocator *allocator_create(unsigned int max);
void allocator_destroy(struct allocator **);
void *allocator_alloc(struct allocator*,int);
void allocator_dealloc(struct allocator*,void*);
#endif
mem_allocator.c
#include "mem_allocator.h
"#include "
../first_fit/first_fit.h
"#include "
../first_fit/first_fit_define.h
"#include "
../fix_obj_pool/fix_obj_pool.h
"#include "
"#include
#include
#include
#include
#define first_fit_default_size 1024*1024*16 //
預設first_fit分配器大小是16mb
/** fix_obj_pool用於分配從1-1024位元組大小的請求
* 請求對齊到4位元組.所以總共有1024/4 = 256種大小
*/struct allocator
;struct head_fix
;struct head_first_fit
;struct chunk;
extern
void *pool_alloc2(struct fix_obj_pool*,unsigned short *chunk_idx);
extern
void pool_dealloc2(struct fix_obj_pool *pool,unsigned short chunk_idx,void* obj);
struct allocator *allocator_create(unsigned int max)
}al->first_fits = vector_create(sizeof(struct first_fit_pool*),0);
struct first_fit_pool *first_fit = first_fit_create(first_fit_default_size);
if(!first_fit)
vector_push_back(struct first_fit_pool*,al->first_fits,first_fit);
return al;
}void allocator_destroy(struct allocator **al)
i = 0;
for( ; i < 1024/4;++i)
free(*al);
*al = 0;
}void *allocator_alloc(struct allocator *al,int size)
if(!hff)
if(!hff)
void *ret = (void*)((char*)hff + sizeof(*hff));
return ret;}}
else
}void allocator_dealloc(struct allocator *al,void *ptr)
}else
}}
IPV6通用原理培訓
描述ipv6的基本特點 列出主流ipv6的網路演進方案 列出ipv6不同的演進方案使用場景 根據現網情況選擇合理的ipv6演進方案 提出了nat方案 nat私網位址轉換為私網位址 該技術為資料報頭轉化為另乙個資料報頭 nat444 即再使用者訪問公共網路之前做兩次nat轉換 ipv4轉ipv4再轉i...
正規表示式6 通用搜尋
上一章提到了模糊搜尋,字元組就是一種,因為它不指定具體哪乙個字元了,那麼,還敢再模糊一些麼?沒問題,這章來看更模糊一些的 通用搜尋 通用搜尋會用到轉義字元,希望能你已經理解了轉義字元。如果還不理解,請回到 轉義搜尋 那章再理解一下。下面是常用的通用搜尋的格式 表示式含義例子.搜尋任意乙個字元,但是不...
C語言學習 6 記憶體分配
一 傳統陣列的缺點 1 陣列的長度必須事先定製,且只能是常整數,不能是變數 intlen 5 inta len error 2 傳統形式定義的陣列,該程式的記憶體程式設計師無法手動釋放 include void f void 這二十個位元組的儲存空間程式設計師無法手動程式設計釋放它 只能在本函式執行...