内存池
内存池是指程序预先从操作系统 申请一块足够大内存 ,此后,当程序中需要申请内存的时候,不是直接向操作系统申请,而是 直接从内存池中获取 ;
同理,当 **程序释放内存 **的时候,并不真正将内存返回给操作系统,而是 返回内存池 。当程序退出( 或者特定时间 ) 时,内存池才将之前申请的内存真正释放。
程序关键
在进行地址归还的时候,必须要使用二级指针,因为获取到头部指针后需要记录下一个内存块的地址,这句话是理解下方程序的关键。
#pragma once
#include <iostream>
#include <vector>
#include <time.h>
using std::cout;
using std::endl;
//定长内存池
//template<size_t N>//非类型模板参数
//class ObjectPool
//{};
//定长内存池
template<class T>
class ObjectPool
{
public:
T* New() {
size_t objsize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
T* obj = NULL;
// step2:申请空间有限从回收链表_freeList里拿
if (_freeList) {
//_freeList每个固定大小的头部字节中都有下一块内存的地址
obj = (T*)_freeList;
_freeList = *(void**)obj;
}
else {
// step1
// 小于1个指针给1个指针的大小
if (_remainBytes < objsize) {
_remainBytes = 128 * 1024;
_memeory = (char*)malloc(_remainBytes);// 开个128kb的空间
if (_memccpy == NULL) {
throw std::bad_alloc();// 直接抛出异常
}
}
obj = (T*)_memeory;
_memeory += objsize;
_remainBytes -= objsize;
}
new(obj)T;// 定位new,就是初始化这段空间
return obj;
}
void Delete(T* obj) {
// step1
// 将这些空间一一连接起来,回收并利用
obj->~T();// 显示调用析构函数
*(void**)obj = _freeList;// *(void**)解引用就是void*的大小,也就是一个指针的大小
//头插入
_freeList = obj;
}
private:
char* _memeory = NULL;// 指向内存块 头部 的指针
size_t _remainBytes = 0;// 指向内存块 剩余 的指针
void* _freeList = NULL;// 指向回收链表的 头指针
};
struct TreeNode
{
int _val;
TreeNode* _left;
TreeNode* _right;
TreeNode()
:_val(0)
, _left(nullptr)
, _right(nullptr)
{
}
};
void TestObjectPool()
{
// 申请释放的轮次
const size_t Rounds = 3;
// 每轮申请释放多少次
const size_t N = 10000;//1w
std::vector<TreeNode*> v1;
v1.reserve(N);
size_t begin1 = clock();
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v1.push_back(new TreeNode);
}
for (int i = 0; i < N; ++i)
{
delete v1[i];
}
v1.clear();
}
size_t end1 = clock();
ObjectPool<TreeNode> TNPool;
std::vector<TreeNode*> v2;
v2.reserve(N);
size_t begin2 = clock();
for (size_t j = 0; j < Rounds; ++j)
{
for (int i = 0; i < N; ++i)
{
v2.push_back(TNPool.New());
}
for (int i = 0; i < N; ++i)
{
TNPool.Delete(v2[i]);
}
v2.clear();
}
size_t end2 = clock();
cout << "new cost time:" << end1 - begin1 << endl;
cout << "object pool cost time:" << end2 - begin2 << endl;
}
可以看到效率的提升