閑來無事對jabberd2服務器閱讀了下,每次讀C++代碼,都首先花費一些額外的時間領會代碼作者的抽象世界概念堆砌當中,C則不同,直入主題,心理上不會有任何負擔,不用徒勞輾轉在不同的世界理解和哲思之中,又一次拜倒在C的簡潔明了之下
^^廢話不多說了開始我們的內容:
內存池實現相當的簡單,由兩個個主要部分組成 pheap,pfree,pool_struct,以及基本的內存池API
pheap: 內存塊,它由pfree組織管理
pfree: 由pheap構成鏈表,它作為內存池實體單元
pool_struct: 內存池結構體
//pool.h文件
//=========================================================================
//于內存池中的實體(內存塊)關聯的回調函數,當實體釋放時調用
typedef void (*pool_cleanup_t)(void *arg);
//單獨內存分塊
struct pheap
{
void *block; //實際的數據內存塊
int size,used; //實際大小,使用大小
};
//帶有釋放內存毀掉函數的內存分塊鏈表結點(內存池實體)
struct pfree
{
pool_cleanup_t f; //內存釋放毀掉函數
void *arg;
struct pheap *heap; //單獨內存分塊
struct pfree *next; //下一個單獨內存分塊
};
//內存池--基于內存池實體。管理一個由內存池實體(pfree)組成的鏈表。
typedef struct pool_struct
{
int size; //內存池大小
struct pfree *cleanup; //鏈表首結點
struct pfree *cleanup_tail; //鏈表尾結點
struct pheap *heap;
#ifdef POOL_DEBUG //調試信息
char name[8], zone[32];
int lsize;
#endif
} _pool, *pool_t;
#ifdef POOL_DEBUG //調式調用函數版本定義宏
# define pool_new() _pool_new(__FILE__,__LINE__)
# define pool_heap(i) _pool_new_heap(i,__FILE__,__LINE__)
#else
# define pool_heap(i) _pool_new_heap(i,NULL,0)
# define pool_new() _pool_new(NULL,0)
#endif
//jabberd2內存池API函數定義
JABBERD2_API pool_t _pool_new(char *file, int line); //構建一個新的內存池
JABBERD2_API pool_t _pool_new_heap(int size, char *file, int line); //構建一個指定初始內存區塊大小的內存池
JABBERD2_API void *pmalloc(pool_t, int size);//封裝 malloc函數,內存從內存池中進行分配,自動完成釋放
JABBERD2_API void *pmalloc_x(pool_t p, int size, char c); /* Wrapper around pmalloc which prefils buffer with c */
JABBERD2_API void *pmalloco(pool_t p, int size); /* YAPW for zeroing the block */
JABBERD2_API char *pstrdup(pool_t p, const char *src); /* wrapper around strdup, gains mem from pool */
JABBERD2_API char *pstrdupx(pool_t p, const char *src, int len); /* use given len */
JABBERD2_API void pool_stat(int full); /* print to stderr the changed pools and reset */
JABBERD2_API void pool_cleanup(pool_t p, pool_cleanup_t fn, void *arg); /* calls f(arg) before the pool is freed during cleanup */
JABBERD2_API void pool_free(pool_t p);//調用所有的內存釋放回調函數,釋放所有內存池中的數據,刪除內存池本身
JABBERD2_API int pool_size(pool_t p); //返回內存中已分配的總字節數
//pool.c文件
//=========================================================================
//構建一個新的空內存池
pool_t _pool_new(char *zone, int line)
{
pool_t p;
while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1);
p->cleanup = NULL; //初始空鏈表
p->heap = NULL; //同上
p->size = 0;
#ifdef POOL_DEBUG
p->lsize = -1;
p->zone[0] = '\0';
snprintf(p->zone, sizeof(p->zone), "%s:%i", zone, line);
sprintf(p->name,"%X",(int)p);
if(pool__disturbed == NULL)
{
pool__disturbed = (xht)1; /* reentrancy flag! */
pool__disturbed = xhash_new(POOL_NUM);
}
if(pool__disturbed != (xht)1)
xhash_put(pool__disturbed,p->name,p);
#endif
return p;
}
//釋放一個內存分塊
static void _pool_heap_free(void *arg)
{
struct pheap *h = (struct pheap *)arg;
_pool__free(h->block); //free數據內存塊
_pool__free(h); //free pheap結構體自身
}
//向內存池中添加內存池實體pfree
static void _pool_cleanup_append(pool_t p, struct pfree *pf)
{
struct pfree *cur;
if(p->cleanup == NULL)//空內存池時
{
p->cleanup = pf;
p->cleanup_tail = pf;
return;
}
//鏈表末尾添加新實體
cur = p->cleanup_tail;
cur->next = pf;
p->cleanup_tail = pf;
}
//創建一個內存池實體
static struct pfree *_pool_free(pool_t p, pool_cleanup_t f, void *arg)
{
struct pfree *ret;
//為內存池實體分配內存
while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1);
ret->f = f; //內存塊釋放回調函數
ret->arg = arg; //回調函數參數
ret->next = NULL;
return ret;
}
//創建一個內存塊,并為其設置內存釋放回調函數
static struct pheap *_pool_heap(pool_t p, int size)
{
struct pheap *ret; //數據內存塊結構體
struct pfree *clean; //內存池實體
//分配內存數據塊結構體內存
while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1);
//分配數據內存塊內存
while((ret->block = _pool__malloc(size)) == NULL) sleep(1);
ret->size = size; //指定數據內存塊大小
p->size += size; //更新內存池總字節數
ret->used = 0;
//生成對應的內存池實體,_pool_heap_free為靜態函數地址,ret為其調用參數
clean = _pool_free(p, _pool_heap_free, (void *)ret);
clean->heap = ret; /* for future use in finding used mem for pstrdup */
_pool_cleanup_append(p, clean);//將內存池實體,添加到內存池實體鏈表中
return ret;
}
//內存池內存請求函數
void *pmalloc(pool_t p, int size)
{
void *block;
if(p == NULL)
{
fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
abort();
}
//如果內存池中沒有可用內存,或者申請的內存過大時,直接從進程堆中申請內存
if(p->heap == NULL || size > (p->heap->size / 2))
{
while((block = _pool__malloc(size)) == NULL) sleep(1); //直接從進程內存堆上分配
p->size += size; //遞增內存池總字節數
_pool_cleanup_append(p, _pool_free(p, _pool__free, block));//生成相應的內存池實體,并添加到內存池實體鏈表中
return block;
}
/* we have to preserve boundaries, long story :) */
if(size >= 4)
while(p->heap->used&7) p->heap->used++;
/* if we don't fit in the old heap, replace it */
// 如果在現有內存塊中沒有足夠的內存,重新申請一塊
if(size > (p->heap->size - p->heap->used))
p->heap = _pool_heap(p, p->heap->size);
//當前內存塊有剩余空間
block = (char *)p->heap->block + p->heap->used; //返回內存區塊有效地址
p->heap->used += size; //更新內存區塊使用情況
return block;
}
//對pmalloc進行封裝并使用參數c的內容預填充新內存塊
void *pmalloc_x(pool_t p, int size, char c)
{
void* result = pmalloc(p, size);
if (result != NULL)
memset(result, c, size);
return result;
}
//方便,安全(為結構體申請空白內存等)
void *pmalloco(pool_t p, int size)
{
void *block = pmalloc(p, size);
memset(block, 0, size);
return block;
}