思路
首先定义ObjectPool类,类成员(char*)_memory提前向系统申请内存。
如果有申请内存的行为,则_memory指针向后移动,将分出的内存给要申请的地方。
如果有归还内存的地方时,选择使用(void*)freeList链表将所有要归还内存链接起来 但是要注意,归还内存内部保存的是下一个归还节点的地址,所以这个归还节点在32位下要大于4字节,64位下大于8字节。 这个链表最后指向nullptr 在链表内部的空间块中保存指向下一个内存块的地址 eg:使用obj指针标记要回收地址的起始位置。 (void**)obj解引用=下一块回收空间的地址。 因为不知道是32位还是64位,无法判断一个指针的大小(不同平台指针大小不同,但常规指针类型解引用大小相同),所以这里强转为二级指针类型再解引用(得到指针类型)就可以保证无论在几位机器,一定可以开辟足够的空间大小存下一块内存的地址
注意:如果归还的内存块大小不够保存一个指针,我们在new的之后就保证一定可以存放一个指针的大小
当这块内存被申请完毕的时候,要继续向系统申请内存,所以还需要一个成员变量_overage来记录剩余空间的大小 当剩余大小不够一个对象大小时就需要重新开辟空间
这个大块内存不需要进行内存释放,因为这个内存伴随进程生命周期,当进程退出时,释放内存。
C++代码
#pragma once
#include<iostream>
using std::cout; using std::endl;
template<class T>
class ObjectPool {
private:
char* _memory;
void* _freeList;
size_t _overage;
public:
ObjectPool() :_memory(nullptr), _freeList(nullptr),_overage(0) {}
T* New() {
T* obj = nullptr;
if (_freeList != nullptr) {
void* next = *((void**)_freeList);
obj = (T*)_freeList;
_freeList = next;
}
else
{
if (_overage < sizeof(T)) {
_overage = 100 * 1024;
_memory = (char*)malloc(_overage);
if (_memory == nullptr) {
throw std::bad_alloc();
}
}
obj = (T*)_memory;
size_t SizeT = sizeof(T) > sizeof(void*) ? sizeof(T) : sizeof(void*);
_memory += SizeT;
_overage -= SizeT;
}
new(obj)T;
return obj;
}
void Delete(T* obj) {
obj->~T();
*(void**)obj = _freeList;
_freeList = obj;
}
};
Release与直接new开空间测试
#include"ObjectPool.h"
#include<vector>
#include<time.h>
using namespace std;
struct TreeNode
{
int _val;
TreeNode* _left;
TreeNode* _right;
TreeNode() :_val(0), _left(nullptr), _right(nullptr) {}
};
int main()
{
size_t N = 1000000;
vector<TreeNode*>vet;
vet.resize(N);
size_t begin = clock();
for (int i = 0; i < vet.size(); i++) {
vet[i]=new TreeNode;
}
for (int i = 0; i < vet.size(); i++) {
delete vet[i];
}
size_t end = clock();
cout << "new TreeNode Time:" << end - begin << endl;
ObjectPool<TreeNode>pool;
size_t begin2 = clock();
for (int i = 0; i < vet.size(); i++) {
vet[i]=pool.New();
}
for (int i = 0; i < vet.size(); i++) {
pool.Delete(vet[i]);
}
size_t end2 = clock();
cout << "ObjectPool New Time:" << end2 - begin2 << endl;
return 0;
}
|