【lesson2】定长内存池的实现

news2024/9/24 3:27:36

文章目录

  • 介绍
  • 定长内存池的设计
  • 定长内存池的实现
    • 需要成员变量
    • 需要的成员函数
    • 定长内存池结构
    • 定长内存池Delete(释放空间)的实现
    • 定长内存池New(申请空间)的实现
  • 定长内存池的实现完整版

介绍

作为程序员(C/C++)我们知道申请内存使用的是malloc,malloc其实就是一个通用的大众货,什么场景下都可以用,但是什么场景下都可以用就意味着什么场景下都不会有很高的性能,下面我们就先来设计一个定长内存池做个开胃菜,当然这个定长内存池在我们后面的高并发内存池中也是有价值的,所以学习他目的有两层,先熟悉一下简单内存池是如何控制的,第二他会作为我们后面内存池的一个基础组件。
在这里插入图片描述

定长内存池的设计

在这里插入图片描述
首先定长内存池的设计我们会向内存申请一大块空间,那么这么一大块空间我们肯定的知道在哪里,所以就用_memory指针指向该块空间
在这里插入图片描述
我们需要定义对象时,我们就只需要向内存池中的_memory申请一个对象大小的字节数就行了

我们被申请出去了一个或者多个对象大小的空间,那么一定会被还回来,所以我们就要对这些还回来的对象空间进行管理。
所以我们需要将这些还回来的对象,用单向链表管理起来
在这里插入图片描述
那么我们是如何用_freeList把一个一个对象链接起来的呢
我们可以用一个对象的前几个字节来存储下一个对象的地址。

定长内存池的实现

需要成员变量

在实现定长内存池之前我们要想,定长内存池需要哪些成员变量?

首先:我们向系统堆申请一定大小的空间,那么我们肯定要知道这块空间在哪里,所以第一个成员变量就是_memory指针,指向我们向系统申请的堆空间。
1._memory指针

其次:我们申请了对象就一定会被还回来,所以就要管理还回来的对象,所以第二个成员变量就是_freeList指针。
2._freeList指针

最后:我们_memory指向申请的堆空间如果一直被申请的话,那么申请的堆空间就一定会被使用殆尽,这时就需要向系统申请新的堆空间,那么我们该如何知道申请的堆空间是否被使用使用殆尽。所以就需要第三个成员变量_remainBytes记录剩余空间
3._remainBytes

需要的成员函数

除了成员变量我们还需要想定长内存池需要哪些成员函数?

首先:我们肯定需要一个成员函数,来为我们提供申请一个对象大小空间的窗口。
跟C++申请空间一样命名为New()。

最后:我们申请了一个对象大小的空间,那么最后肯定是要释放的,所以我们肯定要需要一个函数,来为我们提供释放空间的窗口
跟C++释放空间一样命名为Delete()。

定长内存池结构

在这里插入图片描述

定长内存池Delete(释放空间)的实现

Delete函数的逻辑很简单,我们只要把释放回来的对象空间,链接到_freeList即可,所以我们先实现Delete函数。

但是Delete我们也遇到了一个难题,还回来的是一个对象大小的空间啊,并不是一个对象啊。
那么我们如何把一个对象大小的空间链接到_freeList中呢?
这时我们就可以想到,我们可以一个对象大小空间的前4个字节存储指针的大小。
在这里插入图片描述
但是这时又遇到了一个问题,这个代码在32位平台下是可以的,但是在64位平台下指针是8个字节的该代码就不行了。
这时项目的高手就想到了一个办法。
在这里插入图片描述
在这里插入图片描述
(void**)在32位下解引用*(void**)是一个指针的指针,大小是4个字节。
(void**)在64位下解引用*(void**)也是一个指针的指针,大小是8个字节。

这时我们的问题就迎刃而解。

Delete函数的实现:

void Delete(T* obj)
	{
		// 头插
		*(void**)obj = _freeList;
		_freeList = obj;
	}

定长内存池New(申请空间)的实现

New申请空间的步骤:
1.先查看_freeList是否有空闲的一个对象大小的空间,我们优先把还回来内存块对象,再次重复利用。

if (_freeList)
{
	void* next = *((void**)_freeList);
	obj = (T*)_freeList;
	_freeList = next;
}

2.如果_freeList没有空闲的对象空间,那么就向_memory要一块,对象大小的空间。
但是要的时候我们还得注意_memory指向的系统堆空间是否已经使用殆尽了?
如果已经使用殆尽了,我们得先向系统申请一块大的堆空间。
那么如何判断空间是否已经使用殆尽呢?

// 剩余内存不够一个对象大小时,则重新开大块空间
if (_remainBytes < sizeof(T))
{
	_remainBytes = 128 * 1024;//自己规定的向系统堆空间申请的空间大小
	//_memory = (char*)malloc(_remainBytes);
	_memory = (char*)SystemAlloc(_remainBytes >> 13);//Windows下脱离malloc申请大块空间
	if (_memory == nullptr)
	{
		throw std::bad_alloc();
	}
}

这下我们就不考虑_memory指向的系统堆空间是否已经使用殆尽的问题了。
那么我们接下里就要向_memory要一个对象大小的空间。
那么如何要呢?
首先让obj指针_memory的首地址。
在这里插入图片描述
然后_memory += objSize,也就是_memory += 一个对象的大小。
在这里插入图片描述
这里大小可能也就明白了,为什么要把_memory定义成char的,因为char容易控制

然后我们把obj初始化,然后返给外层就可以了。

obj = (T*)_memory;//先把_memory的地址给obj
//然后计算要多少大小的空间,申请的空间大小 > 一个指针的大小 则用一个对象大小
//如果申请的空间大小 < 一个指针的大小 就用一个指针的大小
//因为我们要用对象的前几个字节存储地址,所以一个对象的大小必须 >= 一个指针
size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
_memory += objSize;
_remainBytes -= objSize;

New函数的实现:

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

		// 优先把还回来内存块对象,再次重复利用
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj = (T*)_freeList;
			_freeList = next;
		}
		else
		{
			// 剩余内存不够一个对象大小时,则重新开大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 128 * 1024;
				//_memory = (char*)malloc(_remainBytes);
				_memory = (char*)SystemAlloc(_remainBytes >> 13);
				if (_memory == nullptr)
				{
					throw std::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;
	}

定长内存池的实现完整版

#pragma once
#include <iostream>
#include <vector>
#include <time.h>
using std::cout;
using std::endl;

#ifdef _WIN32
#include<windows.h>
#else
// 
#endif

// 直接去堆上按页申请空间
inline static void* SystemAlloc(size_t kpage)
{
#ifdef _WIN32
	void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else
	// linux下brk mmap等
#endif

	if (ptr == nullptr)
		throw std::bad_alloc();

	return ptr;
}

template<class T>
class ObjectPool
{
public:
	T* New()
	{
		T* obj = nullptr;

		// 优先把还回来内存块对象,再次重复利用
		if (_freeList)
		{
			void* next = *((void**)_freeList);
			obj = (T*)_freeList;
			_freeList = next;
		}
		else
		{
			// 剩余内存不够一个对象大小时,则重新开大块空间
			if (_remainBytes < sizeof(T))
			{
				_remainBytes = 128 * 1024;
				//_memory = (char*)malloc(_remainBytes);
				_memory = (char*)SystemAlloc(_remainBytes >> 13);
				if (_memory == nullptr)
				{
					throw std::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)
	{
		// 显示调用析构函数清理对象
		obj->~T();

		// 头插
		*(void**)obj = _freeList;
		_freeList = obj;
	}

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

	void* _freeList = nullptr; // 还回来过程中链接的自由链表的头指针
};

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

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

相关文章

C++ Qt开发:运用QJSON模块解析数据

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析…

vue 使用echarts-gl实现3d旋转地图

之前也有使用过echarts开发项目中涉及到的地图功能&#xff0c;当时使用geo来实现地图轮廓&#xff0c;看上去有种3d的感觉。最近闲来无事看了一份可视化大屏的UI设计图&#xff0c;感觉3d旋转地图挺好玩的&#xff0c;今天就来尝试实现下。 首先安装下echarts和echarts-gl依赖…

WebGL开发艺术和创意项目

WebGL提供了强大的图形渲染能力&#xff0c;可以用于开发各种艺术和创意项目。以下是一些使用WebGL开发艺术和创意项目的示例&#xff0c;希望对大家有所帮助。 1.交互式艺术品&#xff1a; 利用WebGL&#xff0c;可以创建具有交互性的艺术品。用户可以与艺术品进行互动、探索和…

正则表达式 文本三剑客

一 正则表达式&#xff1a; 由一类特殊字符及文本字符所编写的模式&#xff0c;其中有些字符&#xff08;元字符&#xff09;不表示字符字面意义&#xff0c;而表示控制或通配的功能&#xff0c;类似于增强版的通配符功能&#xff0c;但与通配符不同&#xff0c;通配符功能是用…

openGauss学习笔记-210 openGauss 数据库运维-常见故障定位案例-谓词下推引起的查询报错

文章目录 openGauss学习笔记-210 openGauss 数据库运维-常见故障定位案例-谓词下推引起的查询报错210.1 谓词下推引起的查询报错210.1.1 问题现象210.1.2 原因分析210.1.3 处理办法 openGauss学习笔记-210 openGauss 数据库运维-常见故障定位案例-谓词下推引起的查询报错 210.…

这些好用小众的知识库软件,快收藏起来

现代企业和团队日益重视知识管理&#xff0c;寻找能提供精准、高效、简便的知识库应用变得尤其重要。而今天&#xff0c;将带给大家三款小众却倍受好评的知识库软件&#xff0c;如果你是寻找有效的信息管理工具的话&#xff0c;那么以下就是你不能错过的秘密武器了&#xff0c;…

由于系统注册表文件丢失或损坏,因此Windows无法加载,如何解决?

问题描述&#xff1a;windows黑屏未能启动&#xff0c;提示由于系统注册表文件丢失或损坏&#xff0c;因此windows无法加载&#xff0c;错误代码&#xff1a;0xc000014c。出现这种问题的原因大多是因为电脑在使用过程中硬件松动&#xff0c;导致出现这种问题。 解决办法: 1. 如…

尝试搭建域

使用window 7 作为dmz 主机 server_2008 作为 预控 前提两台主机都在同一个LAN 下&#xff08;设置一个LAN 区域&#xff09;&#xff0c;同样防火墙关闭状态 首先搞定server 2008 中的域 1. 在计算机属性中选择更改设置中将主机名修改一下&#xff1a; 2. 在server 2008 中…

Java 面向对象进阶 01(黑马)

static案例代码&#xff1a; 代码&#xff1a; public class Student {private String gender;private String name;private int age;public static String teacherName ;public Student() {}public Student(String gender, String name, int age) {this.gender gender;this.…

四、ES集群安全策略设置 X-pack

本文主要是结合ES集群搭建时使用&#xff0c;并且适用于ES7.x以上版本 背景及安全策略方案对比 ES 7.x以下版本默认几乎没有任何安全策略&#xff0c;如果集群IP、端口被暴露&#xff0c;在可访问的情况下任何用户都可以对索引进行管理以及数据的增删改查等&#xff0c;基于此需…

故障脚本的重要作用:预防、诊断与恢复

故障脚本是在信息技术和计算机领域中广泛使用的一种自动化工具&#xff0c;它们的主要目的是预测、诊断和修复系统或软件中的故障。这些脚本在现代技术环境中扮演着至关重要的角色&#xff0c;本文将介绍故障脚本的主要作用。 一、预防性作用 监控和预警 故障脚本可以用于监控系…

互联网加竞赛 基于深度学习的人脸性别年龄识别 - 图像识别 opencv

文章目录 0 前言1 课题描述2 实现效果3 算法实现原理3.1 数据集3.2 深度学习识别算法3.3 特征提取主干网络3.4 总体实现流程 4 具体实现4.1 预训练数据格式4.2 部分实现代码 5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 毕业设计…

idea创建golang项目

目录 1、设置环境 2、创建项目 3、设置项目配置 4、初始化项目 5、安装本项目的外部依赖包 6、运行项目 7、访问页面查看结果 1、设置环境 1 启用 Go Modules 功能go env -w GO111MODULEon 2. 阿里云go env -w GOPROXYhttps://mirrors.aliyun.com/goproxy/,direct上述命…

string的基本概念及常用接口

string的基本概念 本质&#xff1a; string时C风格的字符串&#xff0c;而string本质上是一个类。 string和char*的区别&#xff1a; char*是一个字符指针。而string是一个类&#xff0c;类内部封装了char*&#xff0c;管理这个字符串&#xff0c;是一个char*型的容器。 特…

通过docker构建基于LNMP的WordPress项目

计划通过自定义网络模式&#xff0c;创建一个172.18.0.0/16网段 nginx&#xff1a;172.18.0.2:80 php&#xff1a;172.18.0.3:9000 mysql&#xff1a;172.18.0.4:3306 创建nginx的镜像 准备好nginx的安装包 准备nginx的网页目录和wordpress网站目录以及nginx.conf文件 编…

Mybatis-Plus基础

typora-copy-images-to: img Mybatis Plus 今日目标&#xff1a; 了解mybatisplus的特点能够掌握mybatisplus快速入门能够掌握mybatisplus常用注解能够掌握mybatisplus常用的增删改查能够掌握mybatisplus自动代码生成 1 MybatisPlus简介 1.1 MybatisPlus概述 ​ MyBatis-…

【开源】基于JAVA语言的就医保险管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 科室档案模块2.2 医生档案模块2.3 预约挂号模块2.4 我的挂号模块 三、系统展示四、核心代码4.1 用户查询全部医生4.2 新增医生4.3 查询科室4.4 新增号源4.5 预约号源 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVue…

Microsoft Edge 浏览器报错 提示不安全

网站提示不安全 是因为 Microsoft Edge 开了安全过滤 我们需要把这个关掉 打开浏览器的设置&#xff0c;然后 找到隐私选项 找到下边的Microsoft Defender Smartscreen 关掉 Microsoft Edge 支持 Microsoft Defender SmartScreen | Microsoft Learn win10系统下打开网页提示…

云服务器如何快速部署访问静态页面(个人网站博客等)

1&#xff0c;购买云服务器 2&#xff0c;配置安全项 云服务器ecs下&#xff0c;配置ip、端口所有人都可访问 3&#xff0c;关闭防火墙&#xff0c;将前端静态项目传输到云服务器上 可以使用SecureCRT&#xff0c;本地远程连接到服务器&#xff08;需要用户名与密码&#x…

basic CNN

文章目录 回顾卷积神经网络卷积卷积核卷积过程卷积后图像尺寸计算公式&#xff1a;代码 padding代码 Stride代码 MaxPooling代码 一个简单的卷积神经网络用卷积神经网络来对MINIST数据集进行分类如何使用GPU代码 练习 回顾 下面这种由线形层构成的网络是全连接网络。 对于图像…