前言
内存池_百度百科 (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的地址。文章来源:https://www.toymoban.com/news/detail-666896.html
第一部分可以看出,申请出空间的内容就是下一个空间的地址,如pval = 751d78的下一次申请为p = 0000000000751d78文章来源地址https://www.toymoban.com/news/detail-666896.html
END
到了这里,关于(内存池) 基于嵌入式指针的简单内存池的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!