概述
动态内存池是一种内存管理技术,主要用于提高程序在频繁进行小块内存分配和释放时的效率。相比于传统的malloc/free、new/delete、或其他动态内存分配函数,内存池预先申请一大块连续内存,并将这块大内存分割成多个固定大小或一定范围大小的小内存块,然后以池的方式管理和分发这些小内存块。
内存池一般包括:初始化、分配内存块、回收内存块以及整体释放等功能模块。具体实现时,可以通过数组、链表或树等多种数据结构来组织和追踪空闲内存块的状态。当请求分配内存时,从池中取出一个空闲块。当内存不再使用时,将其归还到内存池中,以便后续复用。
CHP_DynamicMemPool类
在C++中,并没有内置的内存池类。为了方便应用层使用内存池,我们封装了CHP_DynamicMemPool类。CHP_DynamicMemPool类是对动态内存池的封装,适用于需要频繁使用内存块,内存块的总数相对固定,但每个内存块的大小不一样的场景,一般会结合队列使用。CHP_DynamicMemPool类的头文件,可参考下面的示例代码。
#pragma once#include <list>#include "HP_Mutex.h"class CHP_DynamicMemPool{public: CHP_DynamicMemPool(); ~CHP_DynamicMemPool(); void Init(unsigned int uiMaxBlockCount, bool bNeedLock = true); char *Alloc(unsigned int uiBytes); void Release(char *pBuf); void Reset(); unsigned int GetTotalBlockCount(); void GetCurBlockCount(unsigned int &uiUsedCount, unsigned int &uiFreeCount);private: typedef struct _TDynamicMemBlock { char *pBlock; unsigned int uiBlockLen; }TDynamicMemBlock; typedef std::list<TDynamicMemBlock> TDynamicMemBlockList; unsigned int m_uiMaxBlockCount; bool m_bNeedLock; TDynamicMemBlockList m_listUsed; TDynamicMemBlockList m_listFree; CHP_Mutex m_mutexBlockList;};
CHP_DynamicMemPool类有6个公共成员函数,下面逐一进行介绍。
Init:初始化内存池,内存池中含有多个内存块,每个内存块的大小可能不一样。参数uiMaxBlockCount为内存块的最大个数,分配内存时,如果超过内存块的最大个数,则分配失败;参数bNeedLock表示是否需要加锁,默认值为true,如果应用层使用CHP_DynamicMemPool对象时已经加了锁,这里可以传入false。
Alloc:分配指定大小的buffer。内存池中含有一个已使用队列和一个空闲队列,分配buffer时,先从空闲队列中查找是否有符合条件的内存块。如果有,直接返回该内存块;如果没有,则检查所有内存块的数量是否超过内存块的最大个数。如果没有超过,则新建一个合适大小的内存块,并加入已使用队列中。如果超过,且空闲队列非空,则从空闲队列取一个内存块,并重新分配合适大小的内存。参数uiBytes为buffer的大小,单位为字节。返回非NULL表示成功,否则失败。
Release:释放buffer,将其从已使用队列放入到空闲队列中。参数pBuf为之前分配的的buffer指针。
Reset:重置内存池,会释放所有内存块中的内存。
GetTotalBlockCount:获取所有内存块的数量。
GetCurBlockCount:获取已使用内存块和空闲内存块的数量。参数uiUsedCount为已使用内存块的数量,参数uiFreeCount为空闲内存块的数量。
总结
动态内存池具有如下几个优点。
减少内存碎片:由于内存池中分配的是预设大小的内存块,所以在多次分配和回收后,不会像普通动态内存那样产生大量的不连续的、无法利用的小内存区域(即:内存碎片)。
提高分配速度:内存池中的内存分配通常采用简单的算法,比如:队列或者链表,来管理空闲内存块,因此分配和回收的速度比系统调用快得多。尤其是在多线程环境下,可以避免因竞争而导致的性能下降。
减少系统开销:系统级的内存分配器需要维护复杂的空闲内存列表并执行较为耗时的操作,而内存池只需处理局部问题,降低系统调用次数,提高了效率。
可预测性增强:在嵌入式系统中,内存池能够提供更可预测的内存分配行为,有助于满足系统对响应时间和确定性的要求。