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

前言

内存池_百度百科 (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




END

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS的内存管理方法4是通过增加一个内存合并算法来提高内存使用效率。这种方法与前文介绍的第二种方法相似,使用一个大数组来管理内存,定义为`static uint8_t ucHeap\[configTOTAL_HEAP_SIZE\]`。在这种方法中,有三个关键函数用于内存分配和释放。首先是`pvPortMalloc`函数,用于分配内存空间。它接受一个参数`xWantedSize`,表示需要分配的内存大小。然后是`vPortFree`函数,用于释放内存空间。它接受一个参数`pv`,表示要释放的内存指针。最后是`prvInsertBlockIntoFreeList`函数,用于将相邻的小的空闲内存块合并成一个大块,以避免内存泄露。释放内存的具体实现如下所示: ```c void vPortFree(void *pv) { if (pv) { vTaskSuspendAll(); { free(pv); traceFREE(pv, 0); } (void)xTaskResumeAll(); } } ``` 这个函数首先检查传入的内存指针是否为空,然后使用`free`函数释放内存,并调用`traceFREE`函数进行内存追踪。最后,使用`vTaskSuspendAll`和`xTaskResumeAll`函数来保证在释放内存的过程中不会发生任务切换。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [基于freertos的嵌入式系统开发(六)FreeRTOS的内存管理方法4](https://blog.csdn.net/cyjbj/article/details/127031092)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [FreeRTOS --(4)内存管理 heap3](https://blog.csdn.net/zhoutaopower/article/details/106677144)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值