jabberd2的内存池
闲来无事对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); // 返回内存中已分配的总字节数
// =========================================================================
// 于内存池中的实体(内存块)关联的回调函数,当实体释放时调用
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;
}
// =========================================================================
// 构建一个新的空内存池
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;
}