1. 概述
这个内存池库使用内存池技术提供了一种自定义内存管理解决方案。它旨在通过预先分配一大块内存并在其中管理较小的对象,来减少频繁内存分配和释放的开销。
2. 文件及其功能
memorypool.h
-
常量定义:
FREE_LIST_COUNT
:定义内存池中自由链表的数量,值设置为 16。BLOCK_SIZE
:指定内存池分配的每个内存块的大小,默认值为 4096 字节。BASE_OBJ_SIZE
:内存池管理的对象的基本大小,设置为 8 字节。MAX_OBJ_SIZE
:内存池可以处理的对象的最大大小。大于这个大小的对象将使用标准的operator new
进行分配,值为 128 字节。
-
MemoryPool
类:- 这个类封装了内存池的核心功能,包括构造函数、析构函数,以及用于内存初始化、分配和释放的方法。
init(size_t size)
:初始化内存池以处理给定大小的对象。allocate()
:为一个对象分配一块内存。deallocate(void* obj)
:释放先前分配的对象,并将其添加到自由列表中。initMemoryPool()
:初始化内存池中的所有自由列表。getFreeList(size_t index)
:返回对特定自由列表的引用。retrieve(size_t size)
:为给定大小的对象检索一块内存。如果大小大于MAX_OBJ_SIZE
,则使用标准的operator new
。revert(void* obj, size_t size)
:归还先前分配的对象。如果对象大小大于MAX_OBJ_SIZE
,则使用标准的operator delete
。
-
模板函数:
newElement<T>()
:使用内存池为类型为T
的对象分配内存,并在原地构造该对象。deleteElement<T>(T* obj)
:析构类型为T
的对象,并使用内存池释放其内存。
memory.cpp
-
静态内存池数组:
- 定义了一个名为
memoryPool
的MemoryPool
对象数组,大小为FREE_LIST_COUNT
。
- 定义了一个名为
-
MemoryPool
类的实现:- 这里实现了
MemoryPool
类的构造函数、析构函数和所有成员函数。
- 这里实现了
3. 使用方法
包含头文件
要在项目中使用内存池,需要包含memorypool.h
头文件:
cpp
#include "memorypool.h"
初始化内存池
在使用内存池之前,需要对其进行初始化:
cpp
MemoryPool::initMemoryPool();
分配和释放内存
可以使用模板函数newElement
和deleteElement
来分配和释放对象:
cpp
// 分配一个MyClass类型的对象
MyClass* obj = newElement<MyClass>();
// 使用该对象......
// 释放该对象
deleteElement(obj);
手动分配和释放
如果更喜欢直接使用MemoryPool
类的方法,可以这样做:
cpp
// 为大小为sizeof(MyClass)的对象分配内存
void* rawObj = MemoryPool::retrieve(sizeof(MyClass));
MyClass* myObj = new(rawObj) MyClass();
// 使用该对象......
// 析构对象并释放内存
myObj->~MyClass();
MemoryPool::revert(rawObj, sizeof(MyClass));
4. 注意事项
- 对象大小限制 :大于
MAX_OBJ_SIZE
的对象将使用标准的operator new
和operator delete
进行分配。 - 初始化 :在进行任何内存分配之前,必须使用
MemoryPool::initMemoryPool()
初始化内存池。 - 正确销毁:使用内存池时,确保在释放对象内存之前正确地析构对象。
5. 未来改进方向
- 线程安全性:添加线程安全机制,使内存池适用于多线程应用程序。
- 动态配置 :使诸如
FREE_LIST_COUNT
、BLOCK_SIZE
等常量在运行时可配置。
6. 源码
memory.h
#ifndef _MEMORYPOOL_MEMORYPOOL_H_
#define _MEMORYPOOL_MEMORYPOOL_H_
static const size_t FREE_LIST_COUNT = 16;
static const size_t BLOCK_SIZE = 4096;
static const size_t BASE_OBJ_SIZE = 8;
static const size_t MAX_OBJ_SIZE = 128;
class MemoryPool
{
public:
MemoryPool();
~MemoryPool();
void init(size_t size);
void* allocate();
void deallocate(void* obj);
static void initMemoryPool();
static MemoryPool& getFreeList(size_t index);
static void* retrieve(size_t size);
static void revert(void* obj, size_t size);
private:
size_t m_blockSize;
size_t m_objSize;
size_t m_remainBytes;
void* m_pFirstBlock;
char* m_pCurrObj;
void* m_pFreeObj;
};
template <typename T>
T* newElement()
{
T* ptr = static_cast<T*>(MemoryPool::retrieve(sizeof(T)));
new(ptr) T();
return ptr;
}
template <typename T>
void deleteElement(T* obj)
{
obj->~T();
MemoryPool::revert(static_cast<void*>(obj), sizeof(T));
}
#endif
memory.cpp
#include "memorypool.h"
static MemoryPool memoryPool[FREE_LIST_COUNT];
MemoryPool::MemoryPool()
: m_blockSize(BLOCK_SIZE)
, m_objSize(0)
, m_remainBytes(0)
, m_pFirstBlock(nullptr)
, m_pCurrObj(nullptr)
, m_pFreeObj(nullptr)
{
}
MemoryPool::~MemoryPool()
{
void* curr = m_pFirstBlock;
while (curr != nullptr)
{
void* next = *(void**)m_pFirstBlock;
operator delete(curr);
curr = next;
}
}
void MemoryPool::init(size_t size)
{
m_objSize = size;
}
void* MemoryPool::allocate()
{
void* obj = nullptr;
if (m_pFreeObj != nullptr)
{
obj = m_pFreeObj;
m_pFreeObj = *(void**)m_pFreeObj;
}
else
{
if (m_remainBytes < m_objSize)
{
m_remainBytes = m_blockSize;
void* newBlock = operator new(m_blockSize);
*(void**)newBlock = m_pFirstBlock;
m_remainBytes -= sizeof(void*);
m_pFirstBlock = newBlock;
m_pCurrObj = static_cast<char*>(newBlock) + sizeof(void*);
}
obj = m_pCurrObj;
m_pCurrObj += m_objSize;
m_remainBytes -= m_objSize;
}
return obj;
}
void MemoryPool::deallocate(void* obj)
{
*(void**)obj = m_pFreeObj;
m_pFreeObj = obj;
}
void MemoryPool::initMemoryPool()
{
for (size_t i = 0; i < FREE_LIST_COUNT; i++)
{
getFreeList(i).init((i + 1) * BASE_OBJ_SIZE);
}
}
MemoryPool& MemoryPool::getFreeList(size_t index)
{
return memoryPool[index];
}
void* MemoryPool::retrieve(size_t size)
{
if (size > MAX_OBJ_SIZE)
return operator new(size);
return getFreeList((size + BASE_OBJ_SIZE - 1) / BASE_OBJ_SIZE - 1).allocate();
}
void MemoryPool::revert(void* obj, size_t size)
{
if (size > MAX_OBJ_SIZE)
{
operator delete(obj);
return;
}
getFreeList((size + BASE_OBJ_SIZE - 1) / BASE_OBJ_SIZE - 1).deallocate(obj);
}
test.cpp
#include "memorypool.h"
#include <iostream>
#include <new>
// 测试用例
class P1
{
int m_id;
};
class P2
{
int m_id[500];
};
class P3
{
int m_id[10];
};
class P4
{
int m_id[20];
};
// 单轮次申请释放次数
void BenchmarkMemoryPool(size_t ntimes)
{
size_t total_costtime = 0;
size_t begin1 = clock();
try
{
for (size_t i = 0; i < ntimes; i++)
{
P1* p1 = newElement<P1>();
deleteElement<P1>(p1);
P2* p2 = newElement<P2>();
deleteElement<P2>(p2);
P3* p3 = newElement<P3>();
deleteElement<P3>(p3);
P4* p4 = newElement<P4>();
deleteElement<P4>(p4);
}
}
catch (const std::bad_alloc& e)
{
std::cerr << "Memory allocation failed: ";
std::cerr << e.what() << std::endl;
}
size_t end1 = clock();
total_costtime += end1 - begin1;
std::cout << "单轮次申请释放次数: " << ntimes << std::endl;
std::cout << total_costtime << std::endl;
}
void Benchmark(size_t ntimes)
{
size_t total_costtime = 0;
size_t begin1 = clock();
try
{
for (size_t i = 0; i < ntimes; i++)
{
P1* p1 = new P1();
delete p1;
P2* p2 = new P2();
delete p2;
P3* p3 = new P3();
delete p3;
P4* p4 = new P4();
delete p4;
}
}
catch (const std::bad_alloc& e)
{
std::cerr << "Memory allocation failed: ";
std::cerr << e.what() << std::endl;
}
size_t end1 = clock();
total_costtime += end1 - begin1;
std::cout << "单轮次申请释放次数: " << ntimes << std::endl;
std::cout << total_costtime << std::endl;
}
int main()
{
MemoryPool::initMemoryPool();
BenchmarkMemoryPool(100000);
Benchmark(100000);
}