定长内存池设计ConcurrentMemoryPool

news2025/1/11 5:57:02

原理

在这里插入图片描述
还回来的内存用链表串联起来,称为自由链表
内存块自身进行链接,前四个字节存下一个的地址
在这里插入图片描述

结构

template<class T>
class ObjectPool
{
public:
	T* New()
	{
		
	}
private:
	char* _memory = nullptr;  //方便切割
	void* _freeList = nullptr;
};

第一步:先给_memory搞一块大内存

	T* New()
	{
		if (_remainBytes <sizeof(T))  //剩余的内存不够分配一个T的大小,重开一个大空间
		{
			_remainBytes = 128 * 1024;
				_memory = (char*)malloc(_remainBytes); //分配初始的大内存128byte
			if (_memory == nullptr)
			{
				throw bad_alloc();
			}
		}

			T* obj = (T*)_memory;
			_memory += sizeof(T);
			_remainBytes -= sizeof(T);

			return obj;
	}

考虑对象的还回

前四/八个字节空间用来指向
在这里插入图片描述
在这里插入图片描述
采用头插的方式
在这里插入图片描述

new从freeList中优先切出

在这里插入图片描述

T* New()
	{
		T* obj = nullptr;

		//优先利用freeList中的
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj =(T*)_freeList;  //obj指向第一块
			_freeList = next;
			return obj;
		}
		else
		{
			if (_remainBytes < sizeof(T))  //剩余的内存不够分配一个T的大小,重开一个大空间
			{
				_remainBytes = 128 * 1024;
				_memory = (char*)malloc(_remainBytes); //分配初始的大内存128byte
				if (_memory == nullptr)
				{
					throw bad_alloc();
				}
			}

			obj = (T*)_memory;
			_memory += sizeof(T);
			_remainBytes -= sizeof(T);

			return obj;
		}
	}

平台冲突问题,申请值小于一个指针大小(64位平台,指针大小为8byte),则给一个指针。并且保证自由链表在链接时,空间至少能存进下一个对象的地址。

加上obj初始化,显示调用析构函数清理对象(T)

#pragma once
#include <iostream>
using std::cout;
using std::endl;
using std::bad_alloc;
//定长内存池
//template<size_t N>
//class ObjectPool
//{};
template<class T>
class ObjectPool
{
public:
	T* New()
	{
		T* obj = nullptr;

		//优先利用freeList中的
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj =(T*)_freeList;  //obj指向第一块
			_freeList = next;
		}
		else
		{
			if (_remainBytes < sizeof(T))  //剩余的内存不够分配一个T的大小,重开一个大空间
			{
				_remainBytes = 128 * 1024;
				_memory = (char*)malloc(_remainBytes); //分配初始的大内存128byte
				if (_memory == nullptr)
				{
					throw bad_alloc();
				}
			}

			obj = (T*)_memory;
			size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			_memory += objSize;
			_remainBytes -= objSize;
		}
		//定位new,显示调用T的构造函数初始化
		new(obj)T;

		return obj;
	}

	void Delete(T* obj)
	{
		//显示调用析构函数清理对象(T)
		obj->~T();
		//头插
		*(void**)obj = _freeList;
		_freeList = obj;
	} 

private:
	char* _memory = nullptr;  //方便切割  指向大块内存的指针
	size_t _remainBytes = 0;  //大块内存在切分过程中剩余字节数

	void* _freeList = nullptr;//还回来的内存链接到的自由链表的头指针
};

测试性能

用数结构分别对比vector容器下(malloc)std::vector<TreeNode*>和此内存池下ObjectPool的运行时间
ConcurrentMemoryPoll.cpp

// ConcurrentMemoryPool.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "ObjectPool.h"


int main()
{
    TestObjectPool();
    return 0;
}

ObjectPool.h

#pragma once
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::bad_alloc;
//定长内存池
//template<size_t N>
//class ObjectPool
//{};
template<class T>
class ObjectPool
{
public:
	T* New()
	{
		T* obj = nullptr;

		//优先利用freeList中的
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj =(T*)_freeList;  //obj指向第一块
			_freeList = next;
		}
		else
		{
			if (_remainBytes < sizeof(T))  //剩余的内存不够分配一个T的大小,重开一个大空间
			{
				_remainBytes = 128 * 1024;
				_memory = (char*)malloc(_remainBytes); //分配初始的大内存128byte
				if (_memory == nullptr)
				{
					throw bad_alloc();
				}
			}

			obj = (T*)_memory;
			size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
			_memory += objSize;
			_remainBytes -= objSize;
		}
		//定位new,显示调用T的构造函数初始化
		new(obj)T;

		return obj;
	}

	void Delete(T* obj)
	{
		//显示调用析构函数清理对象(T)
		obj->~T();
		//头插
		*(void**)obj = _freeList;
		_freeList = obj;
	} 

private:
	char* _memory = nullptr;  //方便切割  指向大块内存的指针
	size_t _remainBytes = 0;  //大块内存在切分过程中剩余字节数

	void* _freeList = nullptr;//还回来的内存链接到的自由链表的头指针
};

struct TreeNode
{
	int _val;
	TreeNode* _left;
	TreeNode* _right;

	TreeNode()
		:_val(0)
		, _left(nullptr)
		, _right(nullptr)
	{}
};

void TestObjectPool()
{
	// 申请释放的轮次
	const size_t Rounds = 5;

	// 每轮申请释放多少次
	const size_t N = 100000;

	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();

	std::vector<TreeNode*> v2;
	v2.reserve(N);

	ObjectPool<TreeNode> TNPool;
	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;
}

Debug版本
32位
在这里插入图片描述
64位
在这里插入图片描述

Release版本
32位
在这里插入图片描述
64位
在这里插入图片描述
清晰看出,ConcurrentMemoryPool的高效

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/878137.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ATF BL1 UFS初始化简单分析

ATF BL1 UFS初始化分析 1 ATF的下载链接2 ATF BL1 UFS 初始化简易流程图3 ATF BL1 ufs初始化简单过程分析3.1 调用过程3.2 hikey960_ufs_init3.3 dw_ufs_init3.3 ufs_init 以海思hikey960为例来介绍&#xff0c;简单介绍在ATF BL1阶段的初始化处理。 1 ATF的下载链接 https:/…

“解引用“空指针一定会导致段错误吗?

可能有些朋友看见这个标题第一反应是嵌入式的某些内存中,0地址也是可以被正常访问的,所以对0地址的解引用不会发生错误,但我要说的情况不是这个,而是指一个真正的空指针,不仅是c/c中的0,(void*)0,NULL,还有nullptr,一个真正的空指针. 在c语言中,想获得某结构体的成员变量相对偏…

HTTP 协议的基本格式和 fiddler 的用法

目录 一. HTTP 协议 1. HTTP协议是什么 2. HTTP协议的基本格式 HTTP请求 首行 GET和POST方法&#xff1a; 其他方法 经典面试题&#xff1a; URL Header(请求报头)部分 空行 ​HTTP响应 状态码总结: 二、Fiddler的用法 1.Fidder的安装 2.Fidder的使用 一. HTTP 协议 1. H…

netty学习分享(一)

TCP与UDP TCP 是面向连接的、可靠的流协议&#xff0c;通过三次握手建立连接&#xff0c;通讯完成时要拆除连接。 UDP是面向无连接的通讯协议&#xff0c;UDP通讯时不需要接收方确认&#xff0c;属于不可靠的传输&#xff0c;可能会出现丢包现象 端口号&#xff1a; 端口号用…

软考:中级软件设计师:文件管理,索引文件结构,树型文件结构,位示图,数据传输方式,微内核

软考&#xff1a;中级软件设计师: 提示&#xff1a;系列被面试官问的问题&#xff0c;我自己当时不会&#xff0c;所以下来自己复盘一下&#xff0c;认真学习和总结&#xff0c;以应对未来更多的可能性 关于互联网大厂的笔试面试&#xff0c;都是需要细心准备的 &#xff08;1…

数学运算1

正确答案&#xff1a;F 你的答案&#xff1a;E 参考答案&#xff1a;最大排列为100 1 99 2 98 3…51 49 50 所以和为999897…1(100-50)因为是一个圈所以&#xff0c;100和50相接&#xff0c;所以等于5000 知识点&#xff1a;数学运算

工作经验总结:RH850中SP、LP、PC寄存器间联系与入栈出栈操作简单整理

一、RH850系列中SP、LP、PC寄存器简介 SP&#xff1a;栈顶寄存器&#xff0c;保存最新栈顶的地址 LP&#xff1a;链接寄存器&#xff0c;保存函数跳转的地址&#xff08;当没发生调用子函数的操作时候&#xff0c;你可以通过单步调试发现&#xff0c;该寄存器的值不变&#x…

Golang-使用 gvm 进行版本控制

当你想为每个项目切换 go 版本时&#xff0c;gvm (Go Version Manager) 很方便。 这里&#xff0c;我将介绍“如何在Mac上安装gvm”和“如何使用gvm” 使用准备 仅适用于 Mac 的准备工作 按照MacOSX 要求中的说明执行以下命令。 xcode-select --install brew update brew …

JavaFx基础学习【一】:基本认识

一、介绍 JavaFX 是一个开源的下一代客户端应用平台&#xff0c;适用于基于Java构建的桌面、移动端和嵌入式系统。 它是许多个人和公司的共同努力的成果&#xff0c;目的是为开发丰富的客户端应用提供一个现代、高效、功能齐全的工具包。 二、JavaFx应用基本结构 想要开发一款…

浅谈医用IT隔离电源在医院特殊场所接地系统的应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 【摘要】我们国家大部分医院的临床救治和确诊都是利用了医疗电气类设备和医用的医疗仪器&#xff0c;因此这些地方的接地问题应该引起我们的高度的重视。IT系统主要是利用了中性点没有直接接地的方式&#xff0c;所以可以减少电…

【【verilog 典型电路设计之加法器树乘法器】】

verilog 典型电路设计之加法器树乘法器 加法器树乘法器 加法器树乘法器的设计思想是“移位后加”&#xff0c;并且加法运算采用加法器树的形式。乘法运算的过程是&#xff0c;被乘数与乘数的每一位相乘并且乘以相应的权值&#xff0c;最后将所得的结果相加&#xff0c;便得到了…

日常BUG——微信小程序提交代码报错

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;日常BUG、BUG、问题分析☀️每日 一言 &#xff1a;存在错误说明你在进步&#xff01; 一、问题描述 在使用微信小程序开发工具进行提交代码时&#xff0c;报出如下错误&#xff1a; Invalid a…

DDR5内存升级看光威,两款超值DDR5内存条,价格实惠性能强劲

DDR4内存条现在用的人应该占多数&#xff0c;但是时候升级DDR5了&#xff0c;都已经2023年了&#xff0c;国产内存早就崛起了&#xff0c;超值的DDR5内存条选择非常多&#xff0c;特别适合游戏玩家使用&#xff0c;像是光威前段时间推出的两款高端DDR5&#xff0c;神策DDR5 和神…

Java面向对象(内部类)(枚举)(泛型)

内部类 内部类是五大成员之一&#xff08;成员变量、方法、构造方法、代码块、内部类&#xff09;&#xff1b; 一个类定义在另一个类的内部&#xff0c;就叫做内部类&#xff1b; 当一个类的内部&#xff0c;包含一个完整的事物&#xff0c;且这个事务不必单独设计&#xf…

折线分割平面

一、题目 我们看到过很多直线分割平面的题目&#xff0c;今天的这个题目稍微有些变化&#xff0c;我们要求的是n条折线分割平面的最大数目。比如&#xff0c;一条折线可以将平面分成两部分&#xff0c;两条折线最多可以将平面分成7部分&#xff0c;具体如下所示。 Input 输入…

计算机竞赛 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

Docker自动化部署安装(十)之安装SonarQube

这里选择的是&#xff1a; sonarqube:9.1.0-community (推荐使用) postgres:9.6.23 数据库(sonarqube7.9及以后便不再支持mysql&#xff0c;版本太低的话里面的一些插件会下载不成功的) 1、docker-sonarqube.yml文件 version: 3 services:sonarqube:container_name: sonar…

打造专属企业展示小程序

在当今的数字化时代&#xff0c;企业展示小程序已经成为了推广企业形象和吸引客户的重要工具。而如何打造一个专属的企业展示小程序呢&#xff1f;下面将带您一步步操作&#xff0c;通过乔拓云网来实现这一目标。 首先&#xff0c;您需要注册登录乔拓云网并进入操作后台。在乔拓…

如何修复损坏的DOC和DOCX格式Word文件?

我们日常办公中&#xff0c;经常用到Word文档。但是有时会遇到word文件损坏、无法打开的情况。这时该怎么办&#xff1f;接着往下看&#xff0c;小编在这里就给大家带来最简单的Word文件修复方法&#xff01; 很多时候DOC和DOCX Word文件会无缘无故的损坏无法打开&#xff0c;一…