vlambda博客
学习文章列表

C++内存管理-内存池3

因为前面的内存池是针对每一个类,所以我们必须对每一个类重写一遍几乎相同的operator new、operator delete。这在工程代码中是不可以被接受,在项目中最重要的就是不要重复的造轮子。

下面将展示一种写法,将内存池的实现,写为一个operator类,所有想要实现内存池的类只要静态包含,并调用operator类的申请、释放函数即可,这样就使得代码可以重复的被使用。


//内存池分配器 class allocator { private: //和调用的函数共用同一块内存,放入next指针 struct obj { struct obj* next; }; public: //申请内存接口 void* allocate(size_t); //释放内存接口 void deallocate(void*, size_t); private: //内存池头指针 obj* freeStore = nullptr; //每次申请内存个数,可以随意设置 const int CHUNK = 5;  };
void* allocator::allocate(size_t size) { obj* p; //如果内存池为空,则申请CHUNK个内存 if (!freeStore){ size_t chunk = CHUNK * size; freeStore = p = (obj*)malloc(chunk); //将内存池串成一串 for (int i = 0; i < (CHUNK - 1); ++i) { p->next = (obj*)((char*)p + size); p = p->next; } p->next = nullptr; } p = freeStore; freeStore = freeStore->next; return p; }
void allocator::deallocate(void* p, size_t) { //将释放的内存放回内存池中 ((obj*)p)->next = freeStore; freeStore = (obj*)p; }

allocator里面的实现和内存池2里基本一样,只是将其包装成一个独立的类。

所以当我们某一个类(Foo)用到内存池时,就可以这么使用:

class Foo{ public: long L; string str; //类的内存池 static allocator myAlloc; public: Foo(long l):L(l){} //调用内存池获取内存 static void* operator new(size_t size){ return myAlloc.allocate(size); } //调用内存池释放内存 static void operator delete(void* pdead, size_t size) { return myAlloc.deallocate(pdead, size); }};allocator Foo::myAlloc;  void pool_3_test(){ Foo* p[100]; cout << sizeof(Foo) << endl; //申请100个内存 for (int i = 0; i < 100; ++i) { p[i] = new Foo(i); } //查看前11个内存地址 for (int i = 0; i < 11; ++i) { cout << p[i] << " " << p[i]->L << endl; } //delete 申请的内存 for (int i = 0; i < 100; ++i) { delete p[i];    }}

输出结果:

480000022921F9FE30 00000022921F9FE60 10000022921F9FE90 20000022921F9FEC0 30000022921F9FEF0 40000022921FA1C80 50000022921FA1CB0 60000022921FA1CE0 70000022921FA1D10 80000022921FA1D40 90000022921FA1DB0 10

可以看到,因为我们将CHUNK设为5,每5个内存相邻。

总结:

如果我们看STL源码,可以发现,容器在调用分配器(内存池)时,基本都是这种调用方法。其实现原理会比我们简单的链表复杂一些,但是万变不离其宗,内存池是原理总是先申请一片内存,然后集中的去管理它,对内存的申请和释放内存进行实现。