大城小魔

天下难事,必作于易;天下大事,必作于细

  C++博客 ::  :: 联系 :: 聚合  :: 管理

公告


最新评论

 

闲来无事对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 *= (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; //内存块释放回调函数
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;
}


 

 

 

 

posted on 2008-11-13 23:40 momor 阅读(1520) 评论(3)  编辑 收藏 引用 所属分类: C++/C

Feedback

# re: jabberd2的内存池 2008-11-14 10:45 zuhd
这个池能否实现分配不等大小的内存,能否对碎片进行整理?否则和boost没有什么区别  回复  更多评论
  

# re: jabberd2的内存池 2008-11-14 11:04 momor
老实说,本人也认为这个内存池还是很弱,它主要针对保证对内存泄露的控制,预先分配的大内存块,也可以保证内存碎片的产生,一定程度提高了内存块分配的速度,它可以实现不等大小内存的分配。
我个人还是倾向SGI内存池的实现,它根据所需分配的不同内存大小的索引表进行空闲内存链表的管理。逻辑上和功能实现上都比较清晰  回复  更多评论
  

# re: jabberd2的内存池 2008-11-19 13:29 xto
这种内存池可能主要用于效率和性能比较高的地方,例如通信服务端接受数据时用以装载数据的内存区域。如果频繁的新建和释放内存,必然可能会产生内存碎片,更常见的则是cpu在创建和释放内存时性能的损耗。因此才会创建内存池对数据进行处理。其实很多通信服务端常用的线程池,内存池都有这个原理在里面  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理