一.简介
内存池可以提高内存申请的效率,还可以一定程度避免内存泄漏。
这是一个仿照ngnix实现的内存池,学习后把自己的理解写上去了。
二.内存池结构
内存池结构体主要分为三部分,小数据内存分配块,大文件内存分配块,还有一个清理函数部分,他们都是通过链表存储的。
(一).小数据内存分配块
struct ngx_pool_data_t
{
char* last;//已经分配到的地方,可以分配的起始地址
char* end;//数据块大小
ngx_pool_t* next;//下一个数据块
int count;//访问次数
};
这个结构体使用的时候,last记录的是上次分配内存后,剩余内存的起始地址
#include<iostream>
#include<fstream>
using namespace std;
class ngx_pool_t;
struct ngx_pool_data_t
{
char* last;//已经分配到的地方,可以分配的起始地址
char* end;//数据块大小
ngx_pool_t* next;//下一个数据块
int count;//访问次数
};
struct ngx_pool_large_t
{
ngx_pool_large_t* next;//下一个大内存块
void* alloc;//内存的首地址
};
struct ngx_pool_cleanup
{
void* data;
//回调函数
ngx_pool_cleanup* next;
};
struct ngx_pool_log
{
ofstream* pof;
};
struct ngx_pool_t
{
ngx_pool_data_t* d;//数据块
int max;//可以分配内存的最大值
ngx_pool_t* current;//当前块
ngx_pool_large_t* large;//大文件链表
ngx_pool_cleanup* cleanup;//清除链表
ngx_pool_log* log;
};
void ngx_errno_log()
{
}
void* ngx_alloc(size_t size, ngx_pool_log* log)//申请大小为size的空间
{
void* p;
p = malloc(size);
if (p == NULL)
{
//失败打印日志
*(log->pof) << "malloc faild " << endl;
//返回空
return nullptr;
}
//写进日志,malloc:%p size:size
*(log->pof) << "malloc:" << hex << p << "size :" << size << endl;
return p;
}
//把size大小的内存清零
void ngx_memzero(void* p, int size)
{
char *pm = static_cast<char*>(p);
for (int i = 0; i < size; i++)
{
*(pm + i) = 0;
}
}
void* ngx_calloc(size_t size, ngx_pool_log* log)//申请大小为size的空间,并清零
{
void* p;
p = ngx_alloc(size, log);
if (p)
{
ngx_memzero(p, size);
}
return p;
}
//应该有一个内存对其操作,这里只是转换了类型
ngx_pool_t* ngx_calloc_align(int size,ngx_pool_log * log)
{
return static_cast<ngx_pool_t*>(ngx_calloc(size, log));
}
//创建内存池
ngx_pool_t* ngx_pool_create(int size,ngx_pool_log *log)
{
ngx_pool_t* p;
p = ngx_calloc_align(size, log);
if (p == NULL)
{
//打印到日志里初始化失败
*(log->pof) << "ngx_pool_create failed : NULL" << endl;
return NULL;
}
p->d->last = (char*)p + sizeof(ngx_pool_t);//内存分配的起始地址
p->d->count = 0;//该内存块读取次数
p->d->end = (char*)p + size;//这个数据块的结束地址
p->d->next = nullptr;//下一个数据块
p->max = size - sizeof(ngx_pool_t);
p->current = p;
p->large = nullptr;
p->cleanup = nullptr;
p->log = nullptr;
return p;
}
//释放大块
void ngx_free_large(ngx_pool_large_t* t, ngx_pool_log* log)
{
*(log->pof) << "free: " << hex << t->alloc;
free(t->alloc);
}
//销毁内存池
void ngx_destroy_tool(ngx_pool_t* pool)
{
//清除cleanup链表
ngx_pool_cleanup* c;
for (c = pool->cleanup; c; c = c->next)
{
//调用回调函数
}
//清除large链表
ngx_pool_large_t* t;
for (t = pool->large; t; t->next)
{
if (t->alloc != nullptr)
{
//*(pool->log->pof) << "free: " << hex << t->alloc;
//free(t->alloc);
ngx_free_large(t, pool->log);
}
}
//清除数据块
ngx_pool_t *p;
ngx_pool_t* n;
for (p = pool, n = pool->d->next;; p = n, n = n->d->next)
{
free(p);
if (n == nullptr)
{
break;
}
}
}
//重设内存池,清除大块,数据段收回
void ngx_ret_pool(ngx_pool_t* pool)
{
//清除大块
for (ngx_pool_large_t* t = pool->large; t; t = t->next)
{
if (t->alloc == nullptr)
{
ngx_free_large(t, pool->log);
}
}
//清除数据块,就是重设d->last指针
pool->d->last = pool->d->end - sizeof(ngx_pool_t);
for (ngx_pool_t* p = pool->d->next; p; p = p->d->next)
{
p->d->last = p->d->end - sizeof(ngx_pool_data_t);
}
}
//数据块申请
void* ngx_palloc_block(ngx_pool_t* pool, int size)
{
char* m;
//申请新的空间
int psize = pool->d->end - (char*)pool;
ngx_pool_t* pnew = ngx_calloc_align(psize, pool->log);
//设置这片空间
m = (char*)pnew + sizeof(pool->d);
pnew->d->end = (char*)pnew + psize;
pnew->d->last = m + size;
pnew->d->count = 0;
pnew->d->next = nullptr;
ngx_pool_t* p;
for (p = pool->current; p->d->next; p = p->d->next)
{
}
p->d->next = pnew;
return m;
}
//大内存申请
void* ngx_palloc_large(ngx_pool_t* pool, int size)
{
void* m = ngx_alloc(size, pool->log);
ngx_pool_large_t* large;
int n = 1;
for (large = pool->large; large->next; large = large->next)
{
if (large->alloc == nullptr)
{
large->alloc = m;
return m;
}
if (n++ >= 3)
{
break;
}
}
large = (ngx_pool_large_t*)ngx_palloc(pool, size);
if (large == NULL)
{
*(pool->log->pof) << "free :" << hex << m;
free(m);
}
}
//申请一块大小为size的空间
void* ngx_palloc(ngx_pool_t* pool, int size)
{
//返回的起始地址
char* m;
ngx_pool_t* p;
//size小于等于最大值,用数据块分配
if (size <= pool->max)
{
p = pool->current;
do
{
//ngx这里有一个内存对齐
if (p->d->end - size >= p->d->last)
{
m = p->d->last;
p->d->last += size;
return m;
}
p = p->d->next;
} while (p);
return ngx_palloc_block(pool, size);
//遍历data链表没有,就重新申请一个block
}
//走大块内存分配
return ngx_palloc_large(pool, size);
}