閑來無事對jabberd2服務(wù)器閱讀了下,每次讀C++代碼,都首先花費(fèi)一些額外的時間領(lǐng)會代碼作者的抽象世界概念堆砌當(dāng)中,C則不同,直入主題,心理上不會有任何負(fù)擔(dān),不用徒勞輾轉(zhuǎn)在不同的世界理解和哲思之中,又一次拜倒在C的簡潔明了之下
^^廢話不多說了開始我們的內(nèi)容:
內(nèi)存池實(shí)現(xiàn)相當(dāng)?shù)暮唵危蓛蓚€個主要部分組成 pheap,pfree,pool_struct,以及基本的內(nèi)存池API
pheap: 內(nèi)存塊,它由pfree組織管理
pfree: 由pheap構(gòu)成鏈表,它作為內(nèi)存池實(shí)體單元
pool_struct: 內(nèi)存池結(jié)構(gòu)體
//pool.h文件
//=========================================================================
//于內(nèi)存池中的實(shí)體(內(nèi)存塊)關(guān)聯(lián)的回調(diào)函數(shù),當(dāng)實(shí)體釋放時調(diào)用
typedef void (*pool_cleanup_t)(void *arg);
//單獨(dú)內(nèi)存分塊
struct pheap
{
void *block; //實(shí)際的數(shù)據(jù)內(nèi)存塊
int size,used; //實(shí)際大小,使用大小
};
//帶有釋放內(nèi)存毀掉函數(shù)的內(nèi)存分塊鏈表結(jié)點(diǎn)(內(nèi)存池實(shí)體)
struct pfree
{
pool_cleanup_t f; //內(nèi)存釋放毀掉函數(shù)
void *arg;
struct pheap *heap; //單獨(dú)內(nèi)存分塊
struct pfree *next; //下一個單獨(dú)內(nèi)存分塊
};
//內(nèi)存池--基于內(nèi)存池實(shí)體。管理一個由內(nèi)存池實(shí)體(pfree)組成的鏈表。
typedef struct pool_struct
{
int size; //內(nèi)存池大小
struct pfree *cleanup; //鏈表首結(jié)點(diǎn)
struct pfree *cleanup_tail; //鏈表尾結(jié)點(diǎn)
struct pheap *heap;
#ifdef POOL_DEBUG //調(diào)試信息
char name[8], zone[32];
int lsize;
#endif
} _pool, *pool_t;
#ifdef POOL_DEBUG //調(diào)式調(diào)用函數(shù)版本定義宏
# 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內(nèi)存池API函數(shù)定義
JABBERD2_API pool_t _pool_new(char *file, int line); //構(gòu)建一個新的內(nèi)存池
JABBERD2_API pool_t _pool_new_heap(int size, char *file, int line); //構(gòu)建一個指定初始內(nèi)存區(qū)塊大小的內(nèi)存池
JABBERD2_API void *pmalloc(pool_t, int size);//封裝 malloc函數(shù),內(nèi)存從內(nèi)存池中進(jìn)行分配,自動完成釋放
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);//調(diào)用所有的內(nèi)存釋放回調(diào)函數(shù),釋放所有內(nèi)存池中的數(shù)據(jù),刪除內(nèi)存池本身
JABBERD2_API int pool_size(pool_t p); //返回內(nèi)存中已分配的總字節(jié)數(shù)
//pool.c文件
//=========================================================================
//構(gòu)建一個新的空內(nèi)存池
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;
}
//釋放一個內(nèi)存分塊
static void _pool_heap_free(void *arg)
{
struct pheap *h = (struct pheap *)arg;
_pool__free(h->block); //free數(shù)據(jù)內(nèi)存塊
_pool__free(h); //free pheap結(jié)構(gòu)體自身
}
//向內(nèi)存池中添加內(nèi)存池實(shí)體pfree
static void _pool_cleanup_append(pool_t p, struct pfree *pf)
{
struct pfree *cur;
if(p->cleanup == NULL)//空內(nèi)存池時
{
p->cleanup = pf;
p->cleanup_tail = pf;
return;
}
//鏈表末尾添加新實(shí)體
cur = p->cleanup_tail;
cur->next = pf;
p->cleanup_tail = pf;
}
//創(chuàng)建一個內(nèi)存池實(shí)體
static struct pfree *_pool_free(pool_t p, pool_cleanup_t f, void *arg)
{
struct pfree *ret;
//為內(nèi)存池實(shí)體分配內(nèi)存
while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1);
ret->f = f; //內(nèi)存塊釋放回調(diào)函數(shù)
ret->arg = arg; //回調(diào)函數(shù)參數(shù)
ret->next = NULL;
return ret;
}
//創(chuàng)建一個內(nèi)存塊,并為其設(shè)置內(nèi)存釋放回調(diào)函數(shù)
static struct pheap *_pool_heap(pool_t p, int size)
{
struct pheap *ret; //數(shù)據(jù)內(nèi)存塊結(jié)構(gòu)體
struct pfree *clean; //內(nèi)存池實(shí)體
//分配內(nèi)存數(shù)據(jù)塊結(jié)構(gòu)體內(nèi)存
while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1);
//分配數(shù)據(jù)內(nèi)存塊內(nèi)存
while((ret->block = _pool__malloc(size)) == NULL) sleep(1);
ret->size = size; //指定數(shù)據(jù)內(nèi)存塊大小
p->size += size; //更新內(nèi)存池總字節(jié)數(shù)
ret->used = 0;
//生成對應(yīng)的內(nèi)存池實(shí)體,_pool_heap_free為靜態(tài)函數(shù)地址,ret為其調(diào)用參數(shù)
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);//將內(nèi)存池實(shí)體,添加到內(nèi)存池實(shí)體鏈表中
return ret;
}
//內(nèi)存池內(nèi)存請求函數(shù)
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();
}
//如果內(nèi)存池中沒有可用內(nèi)存,或者申請的內(nèi)存過大時,直接從進(jìn)程堆中申請內(nèi)存
if(p->heap == NULL || size > (p->heap->size / 2))
{
while((block = _pool__malloc(size)) == NULL) sleep(1); //直接從進(jìn)程內(nèi)存堆上分配
p->size += size; //遞增內(nèi)存池總字節(jié)數(shù)
_pool_cleanup_append(p, _pool_free(p, _pool__free, block));//生成相應(yīng)的內(nèi)存池實(shí)體,并添加到內(nèi)存池實(shí)體鏈表中
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 */
// 如果在現(xiàn)有內(nèi)存塊中沒有足夠的內(nèi)存,重新申請一塊
if(size > (p->heap->size - p->heap->used))
p->heap = _pool_heap(p, p->heap->size);
//當(dāng)前內(nèi)存塊有剩余空間
block = (char *)p->heap->block + p->heap->used; //返回內(nèi)存區(qū)塊有效地址
p->heap->used += size; //更新內(nèi)存區(qū)塊使用情況
return block;
}
//對pmalloc進(jìn)行封裝并使用參數(shù)c的內(nèi)容預(yù)填充新內(nèi)存塊
void *pmalloc_x(pool_t p, int size, char c)
{
void* result = pmalloc(p, size);
if (result != NULL)
memset(result, c, size);
return result;
}
//方便,安全(為結(jié)構(gòu)體申請空白內(nèi)存等)
void *pmalloco(pool_t p, int size)
{
void *block = pmalloc(p, size);
memset(block, 0, size);
return block;
}