内存池能解的问题:解决频繁调用内存申请释放产生大量的内存碎片,从而导致内存分配失败,还可以降低内存申请的损耗。
我们实现的线程池按照内存的的页 4k大小分为 大块内存申请和小块内存申请(当然也可以按照你自己定义的大小来决定大小块儿的分配),在线程池初始化的时候我们会先分配一个小小块儿内存,至于大块儿内存我们先不管。
下面我们讲讲小块内存节点的数据结构
我们在来看看大块儿内存的分配如下图所示:
下面我们来定义这三种数据结构:
1.小块儿内存节点
struct mp_node_s{
unsigned char *start; //指向已用内存的末端
unsigned char *end; //指向整个小块儿内存的末端
struct mp_node_s * next;
int flags;
}
2.大块儿内存节点
struct mp_large_s{
struct mp_large_s *next;
void *alloc; //指向分配的内存
}
3. 线程池数据结构
struct mp_pool_s{
size_t max; //除了用户可以自定义大小块儿 我们程序自己也要有个限制
struct mp_node_s *current; //小块指针
struct mp_large_s *large; //大块儿指针
struct mp_node_s head[0];
}
内存池的创建
#define MP_ALIGNMENT 32 //对齐方式
#define MAX_ALLOC_BLOCK 4096 //小块
struct mp_pool_s * mp_create_pool(size_t size){
struct mp_pool_s *p;
int ret = posix_memalign(&p,MP_ALIGNMENT,size+sizeof(mp_pool_s)+sizeof(mp_node_s));
if(ret ) return NULL;
p->max = size < MAX_ALLOC_BLOCK ? size:MAX_ALLOC_BLOCK;
p->current = p->head;
p->large = NULL; //大块先不分配
p->head->start = (unsigned char *)p+sizeof(mp_pool_s)+sizeof(mp_node_s);
p->head->end = p->head->start +size;//第一个块的end不会改变每次只是改变的start
p->head->flag = 0;
return p;
}
//调用这个函数申请内存--这里面区分分配大块还是小块内存用户不感知
void * mp_alloc(struct mp_pool_s*pool,size_t size){
if(size <= pool->max) {
struct mp_node_s *p = pool->current;
do{
unsigned char*m = p->start;
if(p->end - p->start >=size){
p->start += size;
return m;
}
p = p->next; //往下找
}while(p);
return mp_alloc_block(pool,size);//没有足够的空间就分配一块内存
}
//分配大块
return mp_alloc_large(pool,size);
}
如上图所示:新分配的小块儿内存采用头部插入法
//原内存池小块儿内存没有足够的空间 则分配新的小块儿内存
static void* mp_alloc_block(struct mp_pool_s* pool,size_t size ){
struct mp_node_s *h = pool->head;
//分配一个小块儿 获取区分大小块儿内存临界值
size_t psize = (size_t)(h->end - (unsigned char*)h);
unsigned char * m = NULL;
int ret = posix_memalign(&m,MP_ALIGNMENT,psize);
if(ret)return NULL;
//加入的内存池小块链表 插入表头
struct mp_node_s * new_node = (struct mp_node_s*)m;
new_node->next = pool->current;
pool->current = new_node;
pool->head = new_node;
new_node->start = (unsigned char*)m+sizeof(mp_node_s)+size;
new_node->end = (unsigned char*)m+sizeof(mp_node_s)+psize;
return m+sizeof(mp_node_s);
}
大块儿内存分配函数
static void* mp_alloc_large(struct mp_pool_s* pool,size_t size ){
void *p = NULL;
int ret = posix_memalign(&p,MP_ALIGNMENT,size);
struct mp_large_s*large = NULL;
for(large = pool->large;large;large = large->next){
if(large->alloc == NULL){
large->alloc = p;
return p;
}
}
}
内存池的销毁
void mp_destory_pool(struct mp_pool_s*pool){
struct mp_large_s *l;
for(l = pool->large;l;l = l->next){
if(l->alloc)
free(l->alloc);
}
//小块释放
struct mp_node_s*n, *h = pool->head->next;
while(h){
n = h->next;
free(h);
h = n;
}
free(pool);
}
释放内存 只对大块儿内存进行释放
void mp_free(struct mp_pool_s* pool,void* p){
struct mp_large_s *l;
for (l = pool->large; l; l = l->next) {
if (p == l->alloc) {
free(l->alloc);
l->alloc = NULL;
return ;
}
}
}
测试函数
int main()
{
int size = 1 << 12;
struct mp_pool_s *p = mp_create_pool(size);
int i = 0;
for (i = 0;i < 10;i ++) {
void *mp = mp_alloc(p, 512);
}
for (i = 0;i < 5;i ++) {
void *l = mp_alloc(p, 8192);
mp_free(p, l);
}
mp_destory_pool(p);
return 0;
}



