(内存池) 基于嵌入式指针的简单内存池

文章目录

  • 前言
  • Code
    • MemoryPool
    • Test
  • 简单讲解
    • 应用方式
    • 参数
    • MemoryPool();
    • ~MemoryPool();
    • void* allocate();
    • void deallocate(void* p);
    • 测试效果
  • END

前言

内存池_百度百科 (baidu.com)

(Memory Pool)是一种内存分配方式,又被称为固定大小区块规划(fixed-size-blocks allocation)。通常我们习惯直接使用new、malloc等API申请分配内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。

内存池的实现方式多种多样,而本文仅实现一个简单的内存池,主要运用到嵌入式指针。

嵌入式指针,指的在数据单元中,用一部分空间保存某一块空间的地址信息。实现方式多种多样。

本示例的代码量非常少,但能够满足最基本的内存池需要的操作。

Code

MemoryPool

#include <cassert>
#include <cstdint>namespace lotus {
template <typename Type, size_t Element_Count>
class MemoryPool {using UNIT_TYPE = uint8_t;static constexpr size_t BLOCK_SIZE = sizeof(Type);private:void* m_buffer = nullptr;void* m_freeHead = nullptr;public:MemoryPool() {static_assert(sizeof(Type) >= sizeof(void*), "size is to small");m_buffer = malloc(BLOCK_SIZE * Element_Count);m_freeHead = nullptr;for (size_t i = 0; i < Element_Count; i += 1) {void* index = (UNIT_TYPE*)m_buffer + (i * BLOCK_SIZE);*(void**)(index) = m_freeHead;m_freeHead = index;}}~MemoryPool() {if (m_buffer) {free(m_buffer);m_buffer = nullptr;}if (m_freeHead) {m_freeHead = nullptr;}}public:void* allocate() {assert(m_freeHead);void* res = m_freeHead;m_freeHead = (void*)(*(void**)m_freeHead);return res;}void deallocate(void* p) noexcept {*(void**)p = m_freeHead;m_freeHead = p;}
};
}  // namespace lotus

Test

#include <iostream>namespace lotus {
template <typename Type, size_t Element_Count>
class MemoryPool {// ...
}
}int main() {using Tp = long long;lotus::MemoryPool<Tp, 100U> pool;{Tp* p1 = (Tp*)pool.allocate();*p1 = 123;printf("p = %p\t val = %lld\n", p1, *p1);Tp* p2 = (Tp*)pool.allocate();*p2 = 123456;printf("p = %p\t val = %lld\n", p2, *p2);pool.deallocate(p1);printf("after free p1\n");Tp* p3 = (Tp*)pool.allocate();printf("p = %p\t val = %lld\n", p3, *p3);}{printf(">> show near allocate()\n");for (int i = 0; i < 10; i += 1) {Tp* p = (Tp*)pool.allocate();printf("p = %p\t pval = %x\n", p, *p);}}
}

简单讲解

应用方式

将数据类型和类型单元数量作为模板参数确定

每次void* allocate()获取一个单元空间。

每次void deallocate(void* p)释放一个空间。请保证传入的是void* allocate()中获取的。


简单解释一下本文使用嵌入式指针的方式:

// p是一个指针,信息是一个地址值
void* p;
// pp = (void**)(p) 将p的信息强转为一个二级指针
// *pp 解引用,表示pp这块地址`的内容`
*(void**)(p);

参数

template <typename Type, size_t Element_Count>
// 数据类型
Type
// 最大申请个数
Element_Count// 保证每个内存单元式8字节
using UNIT_TYPE = uint8_t;
// type的大小作为一个数据块
static constexpr size_t BLOCK_SIZE = sizeof(Type);// 总内存指针
void* m_buffer = nullptr;
// 头指针,时刻指向可分配出的内存地址
void* m_freeHead = nullptr;

MemoryPool();

MemoryPool() {// 确保目前元素大小比指针大小大static_assert(sizeof(Type) >= sizeof(void*), "size is to small");// 一口气申请大内存m_buffer = malloc(BLOCK_SIZE * Element_Count);m_freeHead = nullptr;for (size_t i = 0; i < Element_Count; i += 1) {// 将大内存分块void* index = (UNIT_TYPE*)m_buffer + (i * BLOCK_SIZE);// !核心!嵌入式指针// 总体表现为每后一个空间都保存前一个空间的地址信息*(void**)(index) = m_freeHead;m_freeHead = index;}
}

~MemoryPool();

~MemoryPool() {// 释放内存if (m_buffer) {free(m_buffer);m_buffer = nullptr;}// 仅起视图代理作用,不掌管内存if (m_freeHead) {m_freeHead = nullptr;}
}

void* allocate();

void* allocate() {assert(m_freeHead);// 分配出去的地址void* res = m_freeHead;// 借助嵌入式指针,将head指向下一个空间m_freeHead = (void*)(*(void**)m_freeHead);return res;
}

void deallocate(void* p);

void deallocate(void* p) noexcept {// 嵌入式指针赋值// p的空间的地址保存head的信息*(void**)p = m_freeHead;// head更新为pm_freeHead = p;
}

测试效果

g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0

p = 0000000000751d98     val = 123    
p = 0000000000751d90     val = 123456 
after free p1
p = 0000000000751d98     val = 7675272
>> show near allocate()
p = 0000000000751d88     pval = 751d80
p = 0000000000751d80     pval = 751d78
p = 0000000000751d78     pval = 751d70
p = 0000000000751d70     pval = 751d68
p = 0000000000751d68     pval = 751d60
p = 0000000000751d60     pval = 751d58
p = 0000000000751d58     pval = 751d50
p = 0000000000751d50     pval = 751d48
p = 0000000000751d48     pval = 751d40
p = 0000000000751d40     pval = 751d38

第一部分可以看出,将p1归还后,再申请p3,获得的还是p1的地址。

第一部分可以看出,申请出空间的内容就是下一个空间的地址,如pval = 751d78的下一次申请为p = 0000000000751d78




END

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Numpy学习笔记

科学计算库&#xff08;Numpy&#xff09; 通常数据都能转换成矩阵&#xff0c;行就是每一条样本数据&#xff0c;列就是每个字段的特征&#xff0c;Numpy在矩阵运算上非常高效&#xff0c;可以快速处理数据并进行数据计算。 Numpy基本操作 先导入 import numpy as nparray…

计算机网络第3章(数据链路层)

计算机网络第3章&#xff08;数据链路层&#xff09; 3.1 数据链路层概述3.1.1 概述3.1.2 数据链路层使用的信道3.1.3 三个重要问题 3.2 封装成帧3.2.1 介绍3.2.2 透明传输3.2.3 总结 3.3 差错检测3.3.1 介绍3.3.2 奇偶校验3.3.3 循环冗余校验CRC(Cyclic Redundancy Check)3.3.…

Python Pandas 处理Excel数据 制图

目录 1、饼状图 2、条形统计图 1、饼状图 import pandas as pd import matplotlib.pyplot as plt import numpy as np #from matplotlib.ticker import MaxNLocator # 解决中文乱码 plt.rcParams[font.sans-serif][SimHei] plt.rcParams[font.sans-serif]Microsoft YaHei …

网络聊天室

一、项目要求 利用UDP协议&#xff0c;实现一套聊天室软件。服务器端记录客户端的地址&#xff0c;客户端发送消息后&#xff0c;服务器群发给各个客户端软件。 问题思考 客户端会不会知道其它客户端地址&#xff1f; UDP客户端不会直接互连&#xff0c;所以不会获知其它客…

计算机网络-物理层(三)编码与调制

计算机网络-物理层&#xff08;三&#xff09;编码与调制 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;它们可以统称为消息 数据是运输信息的实体&#xff0c;计算机只能处理二进制数据&#xff0c;也就是比特0和比特1。计算机中…

【Java 动态数据统计图】动态数据统计思路案例(动态,排序,数组)二(113)

需求&#xff1a; 有一个List<Map<String.Object>>,存储了区域的数据&#xff0c; 数据是根据用户查询条件进行显示的&#xff1b;所以查询的数据是动态的&#xff1b;按区域维度统计每个区域出现的次数&#xff0c;并且按照次数的大小排序&#xff08;升序&#…

科技资讯|荷兰电动自行车丢失将被拒保,苹果Find My可以减少丢失

荷兰最大的自行车协会荷兰皇家旅游俱乐部宣布&#xff0c;将不再为胖胎电动自行车提供保险&#xff0c;因为这种自行车的被盗风险极高。 随着电动自行车的销量飙升&#xff0c;胖胎也变得更受欢迎。但问题是&#xff0c;胖胎电动自行车也成为了自行车盗窃者的首选目标。ANWB …

Android 源码下载(详细版)

经典好文推荐,通过阅读本文,您将收获以下知识点: 一、下载AOSP前的准备 二、国内网络下 clone 清华大学开源软件镜像 三、编写Python脚本,开始下载android-10.0.0_r40 源码 四、源码下载工具包 五、参考文献 一、下载AOSP前的准备 想在国内网络下载AOSP源码,需要电脑配置如…

jvm-虚拟机栈

1.栈的存储单位 栈是运行时单位&#xff0c;而堆是存储的单位 栈解决程序的运行问题&#xff0c;即程序如何执行&#xff0c;或者说如何处理数据。堆解决的是数据存储问题&#xff0c;即数据怎么放&#xff0c;放在哪儿 java虚拟机栈 早期也叫java栈&#xff0c;每个线程在创建…

JMETER基本原理

Jmeter基本原理是建立一个线程池&#xff0c;多线程运行取样器产生大量负载&#xff0c;在运行过程中通过断言来验证结果的正确性&#xff0c;可以通过监听来记录测试结果&#xff1b; JMETER是运行在JVM虚拟机上的&#xff0c;每个进程的开销比loadrunner的进程开销大&#x…

组件库的使用和自定义组件

目录 一、组件库介绍 1、什么是组件 2、组件库介绍 3、arco.design 二、组件库的使用 1、快速上手 2、主题定制 3、暗黑模式 4、语言国际化 5、业务常见问题 三、自定义组件 2、组件开发规范 3、示例实践guide-tip 4、业务组件快速托管 一、组件库介绍 1、什么是…

基于Spring Boot的社区诊所就医管理系统的设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的社区诊所就医管理系统的设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java …

Docker安装并配置cAdvisor

Linux下安装Docker请参考&#xff1a;Linux安装Docker 简介 cAdvisor 是 Google 开源的一款用于展示和分析容器运行状态的可视化工具。通过在主机上运行 CAdvisor 用户可以轻松的获取到当前主机上容器的运行统计信息&#xff0c;并以图表的形式向用户展示。 cAdvisor 可以对…

疲劳驾驶检测和识别4:C++实现疲劳驾驶检测和识别(含源码,可实时检测)

疲劳驾驶检测和识别4&#xff1a;C实现疲劳驾驶检测和识别(含源码&#xff0c;可实时检测) 目录 疲劳驾驶检测和识别4&#xff1a;C实现疲劳驾驶检测和识别(含源码&#xff0c;可实时检测) 1.疲劳驾驶检测和识别方法 2.人脸检测方法 3.疲劳驾驶识别模型(Python) &#xf…

[oneAPI] 使用字符级 RNN 生成名称

[oneAPI] 使用字符级 RNN 生成名称 oneAPI特殊写法使用字符级 RNN 生成名称Intel Optimization for PyTorch数据下载加载数据并对数据进行处理创建网络训练过程准备训练训练网络 结果 参考资料 比赛&#xff1a;https://marketing.csdn.net/p/f3e44fbfe46c465f4d9d6c23e38e0517…

Temu闯关日韩受挫?跨境电商卖家如何打磨好营销链路

海外版拼多多 Temu 先后在日本和韩国上线&#xff0c;然而效果不似预期&#xff0c;日韩市场对这套“低价补贴”策略并不买账。作为一个尚未被日韩消费者熟悉的网站&#xff0c;其价格之便宜无法让消费者信任。除此之外更大的问题是&#xff0c;在日本卷不过线下零售与百元店&a…

生信学院|08月25日《SOLIDWORKS PDM帮助企业对设计数据版本的管理应用》

课程主题&#xff1a;SOLIDWORKS PDM帮助企业对设计数据版本的管理应用 课程时间&#xff1a;2023年08月25日 14:00-14:30 主讲人&#xff1a;车立洋 生信科技 PDM专家 1、图纸&文档的版本管理对于企业的重要性 2、SolidWorks PDM对图纸&文档版本的管理 3、SolidW…

Android6:片段和导航

创建项目Secret Message strings.xml <resources><string name"app_name">Secret Message</string><string name"welcome_text">Welcome to the Secret Message app!Use this app to encrypt a secret message.Click on the Star…

【深度学习 | 数据可视化】 视觉展示分类边界: Perceptron模型可视化iris数据集的决策边界

&#x1f935;‍♂️ 个人主页: AI_magician &#x1f4e1;主页地址&#xff1a; 作者简介&#xff1a;CSDN内容合伙人&#xff0c;全栈领域优质创作者。 &#x1f468;‍&#x1f4bb;景愿&#xff1a;旨在于能和更多的热爱计算机的伙伴一起成长&#xff01;&#xff01;&…

JavaWeb+JSP+SQL server学生学籍管理系统设计与实现(源代码+论文+开题报告+外文翻译+答辩PPT)

需求分析 本系统主要是针对各个高校的学生学籍进行管理&#xff0c;系统满足以下几点要求&#xff1a; 系统安全性。由于此系统中的操作都是由用户操作的&#xff0c;所以对于用户的权限设置比较严格。对于数据库&#xff0c;设置了不同用户的权限&#xff0c;不同权限进入不…