? ? ? ? 在上一篇文章中(https://blog.csdn.net/jxcr1984/article/details/119079948)解释为什么要引用内存池.接下来来看内存池的实现.
? ? ? ? 内存池的原理就是先挖一块大的内存出来,然后把大块内存使用嵌入式指针(embedded pointer)串起来.这样就可以避免malloc多出来的那些cookie,从而达到节省空间的目的,而且也可以减少malloc?的调用次数.
? ? ? ? 以下代码参考候捷老师C++内存管理部分:
class allocator{
private:
struct obj{
struct obj* next; // embedded pointer
}
public:
void* allocate(size_t size){
obj* p;
if(!freeStore){
// linked list 为空,申请一大块
size_t chunk = CHUNK * size;
freeStore = p = (obj*)malloc(chunk);
// 将分配得来的一大块内存当作list串起来
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 deallocate(void *p, size_t){
// 将*p收回插入free list前端
((obj*)p)->next = freeStore;
freeStore = (obj*)p;
}
private:
obj* freeStore = nullptr;
const int CHUNK = 5;
}
以上实现了一个简单的内存池,可以通过以下方法调用:
class Foo{
public:
long L; // for test only
static allocator myAlloc;
public:
Foo(long l) : L(l) {}
static void* operator new(size_t size){ // 重写new, 让其调用内存池的allocate
return myAlloc.allocate(size);
}
static void operator delete(void* pdead, size_t size){
return myAlloc.deallocate(phead, size);
}
};
allocator Foo:myAlloc;
int main()
{
cout << "sizeof(Foo)=" << sizeof(Foo) << endl;
Foo* p[10];
for(int i = 0; i < 10; ++i){
p[i] = new Foo(i);
cout << p[i] << ' ' << p[i]->L << endl;
}
for(int i = 0; i < 10; ++i){
delete p[i];
}
}
运行结果见下图:
可以看到在CHUNK范围内的元素的地址是连续的,说明中间没有Header等相关的内容.?
在上述调用代码中,我们要针对调用类Class Foo写一些必要的函数,如重载new/delete,?声明allocator.?如果想调用?allocator类,基本上都需要写这部分代码,既然是重复的,那么可以继续优化,把它们提取出来,?以宏的形式将公用代码提取出来(与MFC很相似),?这样就大大减少allocator调用类的代码,Foo类调用方式不变.
#define DECLARE_POOL_ALLOC() \
public:\
void* operator new(size_t size){return myAlloc.allocate(size);} \
void operator delete(void* pdead, size_t size){return myAlloc.deallocate(pdead, size);}\
protected:\
static allocator myAlloc;
#define IMPLEMENT_POOL_ALLOC(class_name) \
allocator class_name::myAlloc;
class Foo {
DECLARE_POOL_ALLOC()
public:
long L;
public:
Foo(long l) : L(l) {}
};
IMPLEMENT_POOL_ALLOC(Foo);
//以宏的形式将公用代码提取出来,与MFC很相似
|