前言
內(nèi)存池_百度百科 (baidu.com)
(Memory Pool)是一種內(nèi)存分配方式,又被稱(chēng)為固定大小區(qū)塊規(guī)劃(fixed-size-blocks allocation)。通常我們習(xí)慣直接使用new、malloc等API申請(qǐng)分配內(nèi)存,這樣做的缺點(diǎn)在于:由于所申請(qǐng)內(nèi)存塊的大小不定,當(dāng)頻繁使用時(shí)會(huì)造成大量的內(nèi)存碎片并進(jìn)而降低性能。
內(nèi)存池的實(shí)現(xiàn)方式多種多樣,而本文僅實(shí)現(xiàn)一個(gè)簡(jiǎn)單的內(nèi)存池,主要運(yùn)用到嵌入式指針。
嵌入式指針,指的在數(shù)據(jù)單元中,用一部分空間保存某一塊空間的地址信息。實(shí)現(xiàn)方式多種多樣。
本示例的代碼量非常少,但能夠滿(mǎn)足最基本的內(nèi)存池需要的操作。
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);
}
}
}
簡(jiǎn)單講解
應(yīng)用方式
將數(shù)據(jù)類(lèi)型和類(lèi)型單元數(shù)量作為模板參數(shù)確定
每次void* allocate()
獲取一個(gè)單元空間。
每次void deallocate(void* p)
釋放一個(gè)空間。請(qǐng)保證傳入的是void* allocate()
中獲取的。
簡(jiǎn)單解釋一下本文使用嵌入式指針的方式:
// p是一個(gè)指針,信息是一個(gè)地址值
void* p;
// pp = (void**)(p) 將p的信息強(qiáng)轉(zhuǎn)為一個(gè)二級(jí)指針
// *pp 解引用,表示pp這塊地址`的內(nèi)容`
*(void**)(p);
參數(shù)
template <typename Type, size_t Element_Count>
// 數(shù)據(jù)類(lèi)型
Type
// 最大申請(qǐng)個(gè)數(shù)
Element_Count
// 保證每個(gè)內(nèi)存單元式8字節(jié)
using UNIT_TYPE = uint8_t;
// type的大小作為一個(gè)數(shù)據(jù)塊
static constexpr size_t BLOCK_SIZE = sizeof(Type);
// 總內(nèi)存指針
void* m_buffer = nullptr;
// 頭指針,時(shí)刻指向可分配出的內(nèi)存地址
void* m_freeHead = nullptr;
MemoryPool();
MemoryPool() {
// 確保目前元素大小比指針大小大
static_assert(sizeof(Type) >= sizeof(void*), "size is to small");
// 一口氣申請(qǐng)大內(nèi)存
m_buffer = malloc(BLOCK_SIZE * Element_Count);
m_freeHead = nullptr;
for (size_t i = 0; i < Element_Count; i += 1) {
// 將大內(nèi)存分塊
void* index = (UNIT_TYPE*)m_buffer + (i * BLOCK_SIZE);
// !核心!嵌入式指針
// 總體表現(xiàn)為每后一個(gè)空間都保存前一個(gè)空間的地址信息
*(void**)(index) = m_freeHead;
m_freeHead = index;
}
}
~MemoryPool();
~MemoryPool() {
// 釋放內(nèi)存
if (m_buffer) {
free(m_buffer);
m_buffer = nullptr;
}
// 僅起視圖代理作用,不掌管內(nèi)存
if (m_freeHead) {
m_freeHead = nullptr;
}
}
void* allocate();
void* allocate() {
assert(m_freeHead);
// 分配出去的地址
void* res = m_freeHead;
// 借助嵌入式指針,將head指向下一個(gè)空間
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;
}
測(cè)試效果
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歸還后,再申請(qǐng)p3,獲得的還是p1的地址。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-666896.html
第一部分可以看出,申請(qǐng)出空間的內(nèi)容就是下一個(gè)空間的地址,如pval = 751d78的下一次申請(qǐng)為p = 0000000000751d78文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-666896.html
END
到了這里,關(guān)于(內(nèi)存池) 基于嵌入式指針的簡(jiǎn)單內(nèi)存池的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!