简单内存池与定长内存池
Posted 楠c
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单内存池与定长内存池相关的知识,希望对你有一定的参考价值。
内存碎片
最简单的内存池
申请
释放
定长内存池
哈希映射的freelist池
内碎片
对比内碎片与外碎片
实现定长内存池
成员变量
private:
//一大块内存
//char*,+1就是一个字节,容易移动。
char* _memory = nullptr;
//自由链表
//不要节点,存储指针
void* _freeList = nullptr;
//剩余容量
size_t leftSize=0;
使用这个自由链表,将从memory上的对象挂在自由链表
上,同时memory向后移动
挂在freelist上
怎么实现挂起来呢?在下面代码中取内存的头四个字节挂起来的。但是64位下不好办。
怎么解决呢?
但假如你的类型就比较小呢?没办法,只能定义一个静态变量。
namespace zjn{
template<class T>
class ObjectPool
{
public:
~ObjectPool()
{}
//下一个对象,返回值可以是引用
void*& NextObj(void* obj)
{
return *((void**)obj);
}
T* New()
{
//有freeList就去找freelist
T* obj = nullptr;
if (_freeList)
{
obj = (T*)_freeList;
//他头四个字节就是下一个的地址,让下一个做新的头
/*_freeList = (void*)*((int*)_freeList);*/
_freeList = NextObj(obj);
}
else//否则就去看大块内存
{
//大块内存也没有,去malloc
if (leftSize<sizeof(T))
{
//先申请100k
leftSize = 1024 * 100;
_memory = (char*)malloc(leftSize);
//失败抛异常
if (_memory == nullptr)
{
throw std::bad_alloc();
}
}
//走到这两种情况
//1._memory存在,从他上面切割
//2._memory不存在,malloc开出来了
//开空间+初始化
obj = (T*)_memory;
_memory += sizeof(T);
leftSize -= sizeof(T);
}
new(obj)T;//定位new
return obj;
}
//伪删除,实际是放到freelist中
void Delete(T* obj)
{
obj->~T();
//取出前四个字节让他指向上一个头
/**((int*)obj) = (int)_freeList;*/
NextObj(obj) = _freeList;
//让freeList指向新的头
_freeList = obj;
}
};
最开始是这样写的,但是有越界可能
自定义一个类型,用一个节点测试
测试代码
struct TreeNode
{
int val;
TreeNode* left;
TreeNode* right;
TreeNode()
:val(0)
, left(nullptr)
, right(nullptr)
{}
};
void TestObjectPool()
{
ObjectPool<TreeNode> tnPool;
for (size_t i = 0; i < 1000; ++i)
{
TreeNode* node = tnPool.New();
cout << node << endl;
}
}
这个测试的是,之前释放掉的内存,在申请和之前的地址一样。证明了我们复用是成功的。
void TestObjectPool1()
{
ObjectPool<TreeNode> tnPool;
TreeNode* node1 = tnPool.New();
TreeNode* node2 = tnPool.New();
TreeNode* node3 = tnPool.New();
cout << "node1:" << node1 << endl;
cout << "node2:" << node2 << endl;
cout << "node3:" << node3 << endl;
tnPool.Delete(node2);
TreeNode* node4 = tnPool.New();
cout << "node4:" << node4 << endl;
}
void TestTime()
{
size_t begin1=clock();
std::vector<TreeNode*> v1;
for (int i = 0; i < 100000; ++i)
{
v1.push_back(new TreeNode);
}
for (int i = 0; i < 100000; ++i)
{
delete v1[i];
}
v1.clear();
for (int i = 0; i < 100000; ++i)
{
v1.push_back(new TreeNode);
}
size_t end1 =clock();
cout << "new and delete: "<<end1 - begin1 << endl;
ObjectPool<TreeNode> tnPool;
size_t begin2 = clock();
std::vector<TreeNode*> v2;
for (int i = 0; i < 100000; ++i)
{
v2.push_back(tnPool.New());
}
for (int i = 0; i < 100000; ++i)
{
tnPool.Delete(v2[i]);
}
v2.clear();
for (int i = 0; i < 100000; ++i)
{
v2.push_back(new TreeNode);
}
size_t end2 = clock();
cout <<"New() and Delete(): "<<end2 - begin2 << endl;
}
};
之前的释放只是挂在freelist中,那真正的释放是怎么实现呢?
以上是关于简单内存池与定长内存池的主要内容,如果未能解决你的问题,请参考以下文章