小型内存池设计
内存池设计思路
- 降低malloc调用次数
为了减少malloc的次数,考虑能否先统一malloc一大块内存,然后我们自行在进行分割,然后再将分割的小内存块分配给使用者,而不用每次要使用内存的时候进行一次malloc,这样就可以提高效率。 - 减少cookie数量
设计目的
- 提高速度
- 节省空间
例子
ref. C++ Primer 3/e, p.765
#include<cstddef>
#include<iostream>
using namespace std;
class Screen
{
public:
Screen(int x):i(x){};
int get() {return i;}
void* operator new(size_t);
void operator delete(void*, size_t);
private:
Screen* next;//用来指向申请的内存池
static Screen* freeStore;
static const int screenChunk;
private:
int i;//该类数据
};
Screen* Screen::freeStore = 0;
const int Screen::screenChunk = 24;
void* Screen::operator new(size_t size)
{
Screen* p;
if(!freeStore)
{
size_t chunk = screenChunk * size;//申请内存的大小
freeStore = p = reinterpret_cast<Screen*>(new char[chunk]);
//将一大块分割片片,当作linked list串接起来
for(;p!=&freeStore[screenChunk-1];++p)
p->next = p+1;
p->next = 0;
}
p = freeStore;
freeStore = freeStore->next;//指向链表首位
return p;//把链表传回去
}
void Screen::operator delete(void *p, size_t)
{ //将指针回收到单向链表之中,放回前端
(static_cast<Screen*>(p))->next = freeStore;
freeStore = static_cast<Screen*>(p);
}
int main()
{
cout<<sizeof(Screen)<<endl;
size_t const N = 100;
Screen* p[N];
for(int i = 0; i<N; ++i)
p[i] = new Screen(i);
for(int i = 0; i<N; ++i)
cout<<p[i]<<endl;
for(int i = 0; i<N; ++i)
delete p[i];
}
输出结果
从图中可以看到,每个地址之间都相差8,说明没有带cookie。这是因为我们自己重载了new,如果没有的话,那么会自动调用global new,则每个间隔都会是16,因为包含了两个cookie。
启示
这个例子实际上已经将分配器的机制表达出来了,类似于开辟一个池塘的方式,再将池塘进行分割,分配给使用者。但这个例子也有一个缺点,类中还存在一个next指针,增加了类的大小。在下一个例子中,我们将尝试将这个next去除。