大家好,这是我第一篇在CSDN上的博文,本篇主要讨论小型内存池的设计

大家好,这是我第一篇在CSDN上的博文,本人主要研究嵌入式软件相关。
我先自我介绍一下,本人13年华南师大毕业,现在在深圳一家创业公司工作,主要做嵌入式软件开发,开发平台包括windows和linux,接触使用的软件也很多,如Codewarrior、keil、STVD、IAR、VC等,本人写博客主要也是为了和大家交流嵌入式技术,如有错误或者有其他意见也可以向我提出。
最近一个多月都在windows平台上开发一个实时数据库,使用C++语言,此实时数据库的目的在于保存工控应用环境中成千上万的数据量,实时数据库的设计要求要有良好的文件组织,高效的压缩算法,方便的接口以及快速的读写操作,要求对多个模块操作的时间复杂度为常数级别。
在对数据查询、数据写入队列和其他操作命令队列中,需要经常分配和回收内存,使用系统自带的new来分配内存,如果只是小量内存的快速分配和回收,那效率也还可以,但是很多情况下并非满足这样的条件,例如,在对数据查询的时候,如果一个点位保存了成年累月的数据,那么查询出来的数据量无疑是非常庞大而且耗时较长,如果用new来分配内存,到了上万条数据时(在本人机器上大概是1.5万条数据),new的效率明显的下降,分配1.5万条数据内存需要消耗4秒的时间,如果是多线程环境下更长。光是分配内存就要消耗大部分时间,当然这只是单纯的分配,如果还有构造链表之如的操作,那查询的数据的操作在内存上消耗的时间也占用了大部分,还不算上读写文件的操作(之后会有一篇文章讨论文件的读写)。因此需要构造一个内存池来管理这些内存的回收和释放。
本人参考了网上一些高人写的内存池代码,各有春秋,分析整理后,本人的内存池设计如下:
先来个图显示设计结构

内存块示意图

这里分配的内存是以4字节的倍数去分配的,也就是说分配的内存有可能是多出几个字节,对于现在的计算机来说,多出这几个字节也不算是什么问题,后面还会提到,这里的实现是要牺牲一定的内存为代价来达到快速分配的效果。首先使用一个数组来保存这些内存分配信息,可以注意到,这里最大分配的是1024的字节,内存池分配的原则是,少于1024的字节使用内存池分配,多于1024的字节直接使用new来进行分配,这里可以灵活设置,如果内存够大,可以把1024弄成其他也可以,不过我建议,如果一次需要分配这个量的内存,机使用new来更加划算,因为如果最大的分配内存设置太大,则内存池需要为其一次建立一定量的内存块,这样内存占用量突然会很高,需要根据实际情况权衡。这里主要讨论的是小块内存的快速分配和释放,大内存块的分配可以参考其他高人的代码,这里也不再讨论。
当有一个分配内存的请求来时,假如需要申请的内存为253的内存,根据内存池的分配原则,找到下标为253/4+1 = 64的下标,找到对应的内存分配描述信息,从空闲内存链表头中取出内存块,然后让其加到使用链表的队尾,如图所示。
内存块链表变换
然后返回这个内存块中的数据内存指针
这里需要说明一点,每个内存块的成员如下
struct MemBlock
{
MemBlock* next;//下一个块
MemBlock* pre;//前一个块
void* data;//数据内存块
int index;//所属内存描述的下标
};
这里的data+4才是返回给用户使用的内存块,为什么是加4呢?这里多分配了4个字节,用来存储这个data所属的MemBlock指针,这里就是刚才提到的空间换取时间的概念,这样当我们回收内存的时候能找到对应的MemBlock,从而完成回收,回收过程如下
这里写图片描述

最主要的还是操作各指针的指向,一用到指针操作则非常容易出错,本人也是调试了3天左右,才把这个内存池调稳定,测试情况如下,
本人机器为Inter i3处理器,4G的内存,使用new对10万条数据连续分配和回收的情况下(包含链表的压入和弹出的操作),使用时间大概为4秒左右,使用内存池进行分配和回收,所用时间不到300ms,效率有极大的提升。

结尾:本文介绍了一款小型内存池的设计,主要解决在应用中对于小内存块大量分配和回收情况造成内存碎片和分配速度缓慢问题,经测定能耐有效讲的new带来的时间开销,大家有什么修改意见的话可以提出来,本人也虚心接纳,如果需要源码可以在留言或者私信中跟我说,下一篇讨论线程池的实现,谢谢大家的阅读。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章