C++定长内存块的实现

发布于:2025-06-09 ⋅ 阅读:(13) ⋅ 点赞:(0)

内存池

内存池是指程序预先从操作系统 申请一块足够大内存 ,此后,当程序中需要申请内存的时候,不是直接向操作系统申请,而是 直接从内存池中获取
同理,当 **程序释放内存 **的时候,并不真正将内存返回给操作系统,而是 返回内存池 。当程序退出( 或者特定时间 ) 时,内存池才将之前申请的内存真正释放。

程序关键
在进行地址归还的时候,必须要使用二级指针,因为获取到头部指针后需要记录下一个内存块的地址,这句话是理解下方程序的关键。

#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;
}

在这里插入图片描述
可以看到效率的提升


网站公告

今日签到

点亮在社区的每一天
去签到