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

这篇具有很好参考价值的文章主要介绍了(内存池) 基于嵌入式指针的简单内存池。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

内存池_百度百科 (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更新为p
    m_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文章来源地址https://www.toymoban.com/news/detail-666896.html




END

到了这里,关于(内存池) 基于嵌入式指针的简单内存池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于嵌入式linux的OpenSSL源码移植(基于arm64)

    SSL是Secure Sockets Layer(安全套接层协议)的缩写,可以在Internet上提供秘密性传输。Netscape公司在推出第一个Web浏览器的同时,提出了SSL协议标准。其目标是保证两个应用间通信的保密性和可靠性,可在服务器端和用户端同时实现支持。已经成为Internet上保密通讯的工业标准。

    2024年02月11日
    浏览(67)
  • 嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第五天-Linux消息共享内存(物联技术666)

     更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客 物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件,单

    2024年02月01日
    浏览(55)
  • 嵌入式Linux驱动开发 04:基于设备树的驱动开发

    前面文章 《嵌入式Linux驱动开发 03:平台(platform)总线驱动模型》 引入了资源和驱动分离的概念,这篇文章将在前面基础上更进一步,引入设备树的概念。 在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离,但每次调整资源还是会涉及到内核,所以现

    2024年02月16日
    浏览(70)
  • 嵌入式培训机构四个月实训课程笔记(完整版)-Linux系统编程第五天-Linux消息共享内存练习题(物联技术666)

      更多配套资料CSDN地址:点赞+关注,功德无量。更多配套资料,欢迎私信。 物联技术666_嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记-CSDN博客 物联技术666擅长嵌入式C语言开发,嵌入式硬件,嵌入式培训笔记,等方面的知识,物联技术666关注机器学习,arm开发,物联网,嵌入式硬件

    2024年01月24日
    浏览(54)
  • 【嵌入式项目】基于ARM+Linux的车载系统(完整工程资料源码)

            基于ARM+Linux的车载系统演示效果 基于ARM+Linux的车载系统         本项目计划主要应用于家用,办公等领域轿车中实施的基于物联网云平台的车载系统项目,既能够为车主在行驶过程中提供舒适的体验,又能提供一定的安全保障。            基于ARM+Linux的车

    2024年03月26日
    浏览(115)
  • 嵌入式学习之C语言指针部分复习

    今天主要把C语言的指针部分再次认真的复习了一下,对于指针的整体框架有了更加深刻的理解,特别要重点区分函数指针,指针函数,数组指针,指针数组部分,对于这部分的应用非常重要,而且C语言指针部分是面试的重中之重,所以要加强练习才行。 今天的学习是充满动

    2024年02月12日
    浏览(38)
  • 使用Yocto进行嵌入式Linux开发2 第一个基于Poky的系统

    Ubuntu: Fedora 在我们的开发主机系统上安装了所需的软件包后,我们可以使用 Git 下载当前 LTS 版本的 Poky 源代码,命令如下: 下载完成后,poky 目录中的内容如下: 在poky目录中存在oe-init-build-env脚本,用于设置构建环境。 这里,[build-directory] 是一可选参数,用于指定配置环境

    2024年02月08日
    浏览(48)
  • 基于RK3588的嵌入式linux系统开发(二)——uboot源码移植及编译

            由于官方的SDK占用空间较大(大约20GB左右),需要联系相关供应商提供,且官方的SDK通过各种脚本文件进行集成编译,难以理解系统开发的详细过程。本章介绍直接从官方Github网站下载源码进行移植,进行uboot移植及编译,具体内容如下所述: 1.进入官方的github网

    2024年01月16日
    浏览(61)
  • 嵌入式开发——DMA外设到内存

    加强理解DMA数据传输过程 加强掌握DMA的初始化流程 掌握DMA数据表查询 理解源和目标的配置 理解数据传输特点 能够动态配置源数据 需求 实现串口的数据接收,要求采用dma的方式。 数据交互流程 CPU配置好DMA 外部数据发送给串口外设 串口外设触发中断 CPU处理中断逻辑,通知

    2024年02月03日
    浏览(54)
  • 嵌入式Linux实战开发之项目总体概述(基于IMX6ULL)

    现在越来越多的智能设备融入到我们的生活,然而,丰富的设备之下也是有一套基本的运行框架,只是根据不同的需求增减相应的功能从而满足自身的需要。而电子产品量产工具项目,就是实现基础的功能,可以作为一个基础的模版,学成之后便可进行扩展,根据自身需求,

    2024年02月13日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包