内存池的简单实现


当我们频繁的申请内存(new、malloc) 和 释放内存(delete、free) 时,会产生内存碎片,而且申请和释放内存也会增加时间的消耗。内存池就是为了解决该问题,提高效率产生的。

这里使用分段分段连续的内存,来存储多次申请和释放的内存。

  • 内存单元: 定义的内存最小单元
  • 内存块: 一块连续的内存,可以存放多个内存单元
  • 内存池: 用链表的形式管理多个内存块
    MemoryPool

1. 内存单元

下面是内存单元部分定义:

template<typename T>
class MenoryUnit
{
public:
	T unitData;
	MenoryUnit* pNext = nullptr;
};
  • unitData 表示要存储的单元。
  • pNext 指向下一个要赋值的单元。

2. 内存块

template<typename T>
class MemoryBlock
{
public:
	void* data(void) {
		return (MemoryBlock*)m_pData + 1;
	}

	// 创建内存块
	static MemoryBlock* createMemory(MemoryBlock* pHead, int unitSize, int unitCount) {
		int size = sizeof(MemoryBlock) + unitSize * unitCount;
		MemoryBlock* pBlock = (MemoryBlock*)new char[size];
		memset(pBlock, 0, size);
		pBlock->m_pNext = pHead;
		pBlock->m_pData = pBlock;

		return pBlock;
	}

	// 销毁内存块
	void destoryMemoryBlock(void) {
		MemoryBlock* pBlock = this;
		while (pBlock) {
			MemoryBlock *tempBlock = pBlock;
			pBlock = pBlock->m_pNext;

			// 销毁内存块
			delete[] tempBlock->m_pData;
		}
	}

	friend class MemoryPool<T>;
private:
	MemoryBlock* m_pNext = nullptr;
	void *m_pData = nullptr;
};

内存块首部位置保存内存块的信息,这里仅保存了链表下一个节点指针 **m_pNext ** 和整个的数据指针 m_pData,剩下的数据为要存储内存单元的数据。

  • 函数 createMemory 用于创建内存块,需要指定头内存块的指针,内存单元的大小和内存单元的个数。
  • 函数 destoryMemoryBlock 释放内存块,释放时会释放掉以它为链首的后继链的内存块资源。
  • 函数 data 用于获取内存单元块的首地址。

3. 内存池

template<typename T>
class MemoryPool
{
public:
	MemoryPool() {}
	~MemoryPool() {
		// 销毁内存块
		m_pBlockHead->destoryMemoryBlock();
	}
public:
	// 创建一个对象
	T* createObject(void) {
		if (m_pFreeUnit == nullptr)
		{
			// 创建内存块
			m_pBlockHead = MemoryBlock<T>::createMemory(m_pBlockHead, sizeof(MenoryUnit<T>), m_nPerBlockUnitSize);
			MenoryUnit<T>* pUnit = (MenoryUnit<T>*)m_pBlockHead->data();
			m_pFreeUnit = pUnit;

			// 为内存块中所有元素单元空间赋值下一个将要赋值的内容
			for (int i = 0; i < m_nPerBlockUnitSize - 1; ++i) {
				(pUnit + i)->pNext = pUnit + i + 1;
			}
		}
		// 设置下一个被添加的元素的位置
		MenoryUnit<T>* pDestObject = m_pFreeUnit;
		m_pFreeUnit = m_pFreeUnit->pNext;

		// 使用placement new 为内存区域赋值
		::new(pDestObject) T();
		return (T*)&(pDestObject->unitData);
	}

	// 销毁内存对象
	void destoryObject(T* pUnit) {
		if (m_pBlockHead == nullptr)
			return;

		// 循环遍历该元素
		MemoryBlock<T> *pTempBlock = m_pBlockHead;
		while (pTempBlock){
			for (int i = 0; i < m_nPerBlockUnitSize; ++i) {
				MenoryUnit<T> *pTempUnit = (MenoryUnit<T> *)pTempBlock->data() + i;
				if (&(pTempUnit->unitData) == pUnit)
				{
					// 设置为下一个空位置
					pTempUnit->pNext = m_pFreeUnit;
					m_pFreeUnit = pTempUnit;

					pUnit->~T();// 执行析构函数
					return;
				}
			}
			pTempBlock = m_pBlockHead->m_pNext;
		}
	}

private:
	MemoryBlock<T>* m_pBlockHead = nullptr;		// 内存块链表头指针
	int m_nPerBlockUnitSize = 10;				// 每个内存块中元素单元的个数
	MenoryUnit<T> *m_pFreeUnit = nullptr;		// 用来存放下一个添加元素的位置
};

内存池中 有创建元素的函数 createObject 和 删除元素的函数 destoryObject,这里删除不是释放内存,而是将该块内存的状态标记为未被使用的状态。

  • m_pBlockHead: 存储内存块头指针
  • m_nPerBlockUnitSize: 存储每个内存块中元素的个数
  • m_pFreeUnit: 存储将要添加元素的位置地址。

在创建元素时,为了能够初始化类中的内容,使用了 placement new 关于 new和delete 可参考文章 C++中的new和delete


下面时测试代码:

class TestObject
{
public:
	TestObject() {
		std::cout << "Created TestObject_" << m_nCount << std::endl;
		m_nNumber = m_nCount++;
	}

	~TestObject() {
		std::cout << "Deleted TestObject_" << m_nNumber << std::endl;
	}

	void print(void) {
		std::cout << "Object Info: m_nNumber " << m_nNumber << std::endl;
	}

	static int m_nCount;
	int m_nNumber = 1;
};

int TestObject::m_nCount = 1;

int main(int argc, char** argv) {

	MemoryPool<TestObject> memPool;

	std::vector<TestObject*> vector;
	// 创建对象
	for (int i = 0; i < 20; ++i) {
		TestObject* o = memPool.createObject();
		o->print();
		std::cout << "-------------------------" << std::endl;
		vector.push_back(o);
	}
	// 销毁对象
	for (auto iter = vector.begin(); iter != vector.end(); ++iter) {
		memPool.destoryObject(*iter);
	}

	system("pause");
	return 0;
}

测试结果打印输出:

Created TestObject_1
Object Info: m_nNumber 1
-------------------------
Created TestObject_2
Object Info: m_nNumber 2
-------------------------
Created TestObject_3
Object Info: m_nNumber 3
-------------------------
Created TestObject_4
Object Info: m_nNumber 4
-------------------------
Created TestObject_5
Object Info: m_nNumber 5
-------------------------
Created TestObject_6
Object Info: m_nNumber 6
-------------------------
Created TestObject_7
Object Info: m_nNumber 7
-------------------------
Created TestObject_8
Object Info: m_nNumber 8
-------------------------
Created TestObject_9
Object Info: m_nNumber 9
-------------------------
Created TestObject_10
Object Info: m_nNumber 10
-------------------------
Created TestObject_11
Object Info: m_nNumber 11
-------------------------
Created TestObject_12
Object Info: m_nNumber 12
-------------------------
Created TestObject_13
Object Info: m_nNumber 13
-------------------------
Created TestObject_14
Object Info: m_nNumber 14
-------------------------
Created TestObject_15
Object Info: m_nNumber 15
-------------------------
Created TestObject_16
Object Info: m_nNumber 16
-------------------------
Created TestObject_17
Object Info: m_nNumber 17
-------------------------
Created TestObject_18
Object Info: m_nNumber 18
-------------------------
Created TestObject_19
Object Info: m_nNumber 19
-------------------------
Created TestObject_20
Object Info: m_nNumber 20
-------------------------
Deleted TestObject_1
Deleted TestObject_2
Deleted TestObject_3
Deleted TestObject_4
Deleted TestObject_5
Deleted TestObject_6
Deleted TestObject_7
Deleted TestObject_8
Deleted TestObject_9
Deleted TestObject_10
Deleted TestObject_11
Deleted TestObject_12
Deleted TestObject_13
Deleted TestObject_14
Deleted TestObject_15
Deleted TestObject_16
Deleted TestObject_17
Deleted TestObject_18
Deleted TestObject_19
Deleted TestObject_20


作者:douzhq
个人主页:https://www.douzhq.cn
文章同步页:https://douzhq.cn/memory_pool_page/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值