手写简单内存池(c和c++)
这是实现内存池功能的四个接口,分别是初始化内存池,销毁内存池,分配内存块,释放内存块。代码看着蛮清晰易懂的,唯一的难点可能是*(char**)这个指针的操作,以init函数中的为例:先是拿到指向空余内存块的指针,然后循环内存块,将ptr指针强转为二级指针再解引用,也就是每个内存块中的首部包含了一个char*,指向下一个节点,从而形成了一个链表。fastdfs,MongoDB,ZK,流媒体,CDN,
手写内存池
概要
纯c和cpp实现的简单内存池,均是申请固定大小的内存块
内存池使用以及作用
内存池技术是一种优化内存管理的方法,它通过预先分配一块连续的内存空间,可以将其设置成固定大小块,也可以随机分配(本文是采用固定大小内存块)。之后在程序中使用这些内存块,这样可以减少频繁的动态内存分配和释放操作,从而提高性能和效率。
内存块的作用主要有两点:一是使用内存池技术可以避免内存碎片化问题,并减少了系统调用次数,节省了时间开销。二是内存池还可以提供更好的局部性,因为相邻的对象通常在物理上也是相邻的,这有助于提高缓存命中率,能够提升分配和归还的速度。
纯c实现内存池
typedef struct mempool_s
{
int block_size;
int free_count;
char* free_ptr;
char* mem;
}mempool_t;
内存池结构体,包括内存池的固定块大小,空闲块个数,指向空闲区域的头指针以及指向整个内存池的指针。
主要接口
int mp_init(mempool_t* m,int size){
if(!m)return -1;
if(size<16)size=16;
m->block_size=size;
m->mem=(char*)malloc(MEM_PAGE_SIZE);
if(!m->mem)return -1;
m->free_ptr=m->mem;
m->free_count=MEM_PAGE_SIZE/size;
int i=0;
char* ptr=m->free_ptr;
for(;i<m->free_count;++i){
*(char**)ptr=ptr+size;
ptr+=size;
}
*(char**)ptr=NULL;
}
void mp_destory(mempool_t* m){
if(!m||!m->mem)return;
free(m->mem);
}
void* mp_malloc(mempool_t* m){
if(!m||m->free_count==0)return NULL;
void* ptr=m->free_ptr;
m->free_ptr=*(char**)ptr;
m->free_count--;
return ptr;
}
void mp_free(mempool_t* m,void* ptr){
*(char**)ptr=m->free_ptr;
m->free_ptr=(char*)ptr;
m->free_count++;
}
这是实现内存池功能的四个接口,分别是初始化内存池,销毁内存池,分配内存块,释放内存块。代码看着蛮清晰易懂的,唯一的难点可能是*(char**)这个指针的操作,以init函数中的为例:先是拿到指向空余内存块的指针,然后循环内存块,将ptr指针强转为二级指针再解引用,也就是每个内存块中的首部包含了一个char*,指向下一个节点,从而形成了一个链表。
测试
int main(){
mempool_t m;
mp_init(&m,32);
void* p1=mp_malloc(&m);
printf("mp_malloc:%p\n",p1);
void* p2=mp_malloc(&m);
printf("mp_malloc:%p\n",p2);
void* p3=mp_malloc(&m);
printf("mp_malloc:%p\n",p3);
void* p4=mp_malloc(&m);
printf("mp_malloc:%p\n",p4);
mp_free(&m,p2);
void* p5=mp_malloc(&m);
printf("mp_malloc:%p\n",p5);
}
测试结果
结果是合理的。
cpp实现简单内存池
class mempool
{
public:
int m_size;
int m_count;
static char* m_pool; //起始地址
static bool initpool(){
m_pool=(char*)malloc(18);
if(!m_pool)return false;
memset(m_pool,0,18);
cout<<"内存池的起始地址是"<<(void*)m_pool<<endl;
return true;
}
static void freepool(){
if(!m_pool)return;
free(m_pool);
cout<<"内存池以释放"<<endl;
}
mempool(int size,int count){
m_size=size;
m_count=count;
cout<<"调用了mempool的构造函数"<<endl;
}
~mempool(){
cout<<"调用了mempool的析构函数"<<endl;
}
void* operator new(size_t size){
if(m_pool[0]==0){
cout<<"分配第一块内存:"<<(void*)(m_pool+1)<<endl;
m_pool[0]=1;
return m_pool+9;
}
if(m_pool[9]==0){
cout<<"分配第一块内存:"<<(void*)(m_pool+1)<<endl;
m_pool[9]=1;
return m_pool+9;
}
void* ptr=malloc(size);
cout<<"申请到的内存地址是:"<<ptr<<endl;
return ptr;
}
void operator delete(void* ptr){
if(ptr==0)return;
if(ptr==m_pool+1)
{
cout<<"释放了第一块内存"<<endl;
m_pool[0]=0;
return;
}
if(ptr==m_pool+9)
{
cout<<"释放了第二块内存"<<endl;
m_pool[9]=0;
return;
}
free(ptr);
}
};
char* mempool::m_pool=0;
这是内存池类的实现,其中重载了delete和new运算符(为一个类重载delete/new运算符时,虽然不必显示声明static,但是仍是在创建静态成员函数)。所以,m_poll也需要定义为static成员变量,并在类外初始化。
当内存池用完了的时候,一般有三种方法:1.扩展内存池 2.直接向系统申请内存 3.返回空地址,具体看情况定,本文使用的第二种。
测试
int main(){
if(mempool::initpool()==false){
cout<<"初始化失败"<<endl;
}
mempool* m1=new mempool(8,1);
cout<<"m1的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
mempool* m2=new mempool(8,1);
cout<<"m2的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
mempool* m3=new mempool(8,1);
cout<<"m3的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
delete m1;
mempool* m4=new mempool(8,1);
cout<<"m4的地址是:"<<m1<<"大小:"<<m1->m_size<<"块数:"<<m1->m_count<<endl;
delete m2;
delete m3;
delete m4;
mempool::freepool();
}
测试结果
结果是合理的。
到这,一个简单的内存池模型就完成了。
更多推荐
所有评论(0)