【lesson2】定长内存池的实现
文章目录
- 介绍
- 定长内存池的设计
- 定长内存池的实现
- 需要成员变量
- 需要的成员函数
- 定长内存池结构
- 定长内存池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 _WIN32void* ptr = VirtualAlloc(0, kpage << 13, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
#else// linux下brk mmap等
#endifif (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; // 还回来过程中链接的自由链表的头指针
};
相关文章:

【lesson2】定长内存池的实现
文章目录 介绍定长内存池的设计定长内存池的实现需要成员变量需要的成员函数定长内存池结构定长内存池Delete(释放空间)的实现定长内存池New(申请空间)的实现 定长内存池的实现完整版 介绍 作为程序员(C/C)我们知道申请内存使用的…...

C++迷宫游戏详解
个人主页:[PingdiGuo_guo] 收录专栏:[C干货专栏] 大家好呀,我是PingdiGuo_guo,今天我们来学习用C实现一个迷宫游戏。 目录 1.迷宫的具体步骤 1.1.迷宫的初始化 1.2.寻路算法 1.DFS算法 2.BFS算法 1.3.移动 2.总结 C迷宫游…...
java下载网络文件
/*** 下载文件** param fileId* param response* throws Exception*/ GetMapping("/downLoadFile") public void downLoadFile(Long fileId, HttpServletResponse response) throws Exception{// 根据文件ID查询文件路径FileDO fileDO fileService.get(fileId);// 定…...

大数据信用报告查询费用一般要多少钱?
一些不少朋友在申贷的时候被拒贷之后,得到的原因就是因为大数据不良被拒,这时候很多人都反过来查询自己的大数据信用报告,而查询的价格也是不少朋友都比较关注的,那大数据信用报告查询费用一般要多少钱呢?下面本文就为你介绍一下…...

【操作宝典】IntelliJ IDEA新建maven项目详细教程
目录 🌼1. 配置maven环境 🌼2. 创建maven项目 🌼3. 创建maven项目完整示例 a. 导入spring boot环境 b. 修改maven配置 c. 下载jar包 d. 创建Java类 🌼1. 配置maven环境 【安装指南】maven下载、安装与配置详细教程-CSDN博客…...

【Java程序设计】【C00196】基于(JavaWeb+SSM)的旅游管理系统(论文+PPT)
基于(JavaWebSSM)的旅游管理系统(论文PPT) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的旅游平台 本系统分为前台、管理员2个功能模块。 前台:当游客打开系统的网址后,首先看到的…...

pdmodel从动态模型转成静态onnx
1.下载项目 git clone https://github.com/jiangjiajun/PaddleUtils.git 2.新建两个新的文件夹 第一个文件夹放两个必要文件 第二个文件夹可以设置为空,用来存放转换后的模型 如图: 3.在终端运行 python paddle/paddle_infer_shape.py --model_dir …...

git 如何修改仓库地址
问题背景:组内更换大部门之后,代码仓的地址也迁移了,所以原来的git仓库地址失效了。 虽然重新建一个新的文件夹,再把每个项目都git clone一遍也可以。但是有点繁琐,而且有的项目本地还有已经开发一半的代码,…...

基于springboot篮球论坛系统源码和论文
首先,论文一开始便是清楚的论述了系统的研究内容。其次,剖析系统需求分析,弄明白“做什么”,分析包括业务分析和业务流程的分析以及用例分析,更进一步明确系统的需求。然后在明白了系统的需求基础上需要进一步地设计系统,主要包罗软件架构模式、整体功能模块、数据库设计。本项…...

【三维重建】运动恢复结构(SfM)
运动恢复结构是通过三维场景的多张图像,恢复出该场景的三维结构信息以及每张图片对应的摄像机参数。 欧式结构恢复(内参已知,外参未知) 欧式结构恢复问题: 已知:1、n个三维点在m张图像中的对应点的像素坐标 2、相机内参 求解&…...

Android Studio非UI线程修改控件——定时器软件
目录 一、UI界面设计 1、UI样式 2、XML代码 二、功能编写 1、定义 2、实现方法 3、功能实现 一、UI界面设计 1、UI样式 2、XML代码 <?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android…...

canvas的一些基础
在 Canvas 中,基本图形有两种:直线图形和曲线图形 直线图形:直线、矩形(描边矩形和填充矩形)、多边形 曲线图形:曲线和弧线(弧线是圆的一部分,曲线则不一定,弧线上的每个点都具有相同的曲率&…...

C++(10)——类与对象(最终篇)
目录 static成员 概念 特性 友元 友元函数 友元类 内部类 匿名对象 经过这么多天的分享,C的类与对象终于要结束了。结束也意味着C快要入门了。 static成员 概念 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之…...
NetApp FAS2750 和 FAS2820 简化分布式企业的存储
拥有分布式企业和多个办公位置的客户希望使用这些系统进行虚拟化,以及为大型 FAS 和 AFF 系统提供简单且经济高效的备份和灾难恢复。 NetApp FAS2750 的规格 非常适合需要轻松部署和简化运维的中小型企业。 • 每个 HA 对的最大原始容量:1.2 PB • 每个…...

Geogebra设置函数定义域
曲线方程设置范围 y 4x 0 / (-4 < y < 4) 函数设置范围 函数(e^x*(2x-1),-2.5,3/4)...

代码随想录刷题笔记 DAY 18 | 找树左下角的值 No.513 | 路经总和 No.112 | 从中序与后序遍历序列构造二叉树 No.106
Day 18 01. 找树左下角的值(No. 513) 题目链接 代码随想录题解 1.1 题目 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root [2,1,3] 输出: 1 示例 2: 输入…...

【algorithm】一个简单的PID工程 base 用于手生时候快速复习 用于设计模式 cpp语法八股 快速复习校验
写在前面 最近项目一直用matlab,防止手生整一个回忆工具使用的简单的pid demo,走一边流程,包括配工程debug看结果,复用之前记录的配置见我的bloghttps://blog.csdn.net/weixin_46479223/article/details/135082867?csdn_share_t…...

Python处理图片生成天际线(2024.1.29)
1、天际线简介 天际线(SkyLine)顾名思义就是天空与地面的边界线,人站在不同的高度,会看到不同的景色和地平线,天空与地面建筑物分离的标记线,不得不说,每天抬头仰望天空,相信大家都可…...

jsp服装穿搭推荐系统Myeclipse开发mysql数据库web结构java编程计算机网页项目
一、源码特点 JSP 游戏网上商城系统是一套完善的java web信息管理系统,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发,数据库为Mysql5.0…...

Opencv(C++)学习 之RV1126平台的OPENCV交叉编译
本文特点:网上已经有了很多opencv移植RV1106的文章,本文主要记录基于cmake-gui编译,碰到的报错,及解决报错问题的方法,同时简单总结一些配置项相关的知识。 一、环境: ubuntu18 x64 RV1126交叉编译工具链 …...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

跨链模式:多链互操作架构与性能扩展方案
跨链模式:多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈:模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展(H2Cross架构): 适配层…...
Linux云原生安全:零信任架构与机密计算
Linux云原生安全:零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言:云原生安全的范式革命 随着云原生技术的普及,安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测,到2025年,零信任架构将成为超…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...

MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...