C++定长内存块的实现

内存池

内存池是指程序预先从操作系统 申请一块足够大内存 ,此后,当程序中需要申请内存的时候,不是直接向操作系统申请 ,而是 直接从内存池中获取 ;

同理,当 **程序释放内存 **的时候,并不真正将内存返回给操作系统,而是 返回内存池 。当程序退出( 或者特定时间 ) 时,内存池才将之前申请的内存真正释放。

程序关键

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

cpp 复制代码
#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;
}

可以看到效率的提升

相关推荐
CCCCCCCCharlie12 分钟前
深入解析I/O底层:文件描述符与缓冲区真相
linux·开发语言·c++·算法
自信1504130575922 分钟前
重生之从0开始学习c++之string(下)
c++·学习·stl
wuminyu1 小时前
Continuation::freeze与thaw的x86_64汇编Stack Chunk拆解源码分析
java·linux·c语言·汇编·jvm·c++
kunicoding2 小时前
C++ 策略模式实战:写一个可以“一键换输出“的日志系统
开发语言·c++·策略模式
xiaoye-duck2 小时前
《C++ 项目:手写大模型接入 SDK》项目背景、目标及名词解释
服务器·网络·c++·语言模型
艾莉丝努力练剑2 小时前
【AI大模型接入SDK】ChatServer接口设计规范
网络·c++·人工智能·学习·大模型·设计规范
纪念 2292 小时前
C++算法(三)
开发语言·c++·算法
AbandonForce2 小时前
递归、搜索与回溯:从板书到二叉树解题方法
c++·算法·决策树
艾莉丝努力练剑3 小时前
【AI大模型接入SDK】ChatServer HTTP接口模块实现总览
网络·c++·人工智能·网络协议·学习·http·架构
坤坤子吖3 小时前
Linux 线程概念与控制——线程创建、退出与等待
linux·开发语言·c++·笔记·学习