C++内存池如何实现


这篇文章主要介绍了C++内存池如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++内存池如何实现文章都会有所收获,下面我们一起来看看吧。池化技术是计算机中的一种设计模式,主要是指:将程序中经常要使用的计算机资源预先申请出来,由程序自己管理,程序在使用时直接从“池”中获取,不仅保证了程序占有的资源数量同时减少资源的申请和释放时间。常见的池化技术有内存池、线程池、连接池等。内存池是一种动态内存分配与管理技术。它的核心思想是:预先申请一段内存空间,使用一种高效的数据结构(哈希、链表)进行管理,当程序需要内存时直接从内存池中分配一块内存给程序,同样当使用完时在归还给内存池。这样做的好处是,减少直接使用new/delete、malloc/free等API申请和释放内存的时间,提高程序运行效率;同时,程序每次直接使用new/delete、malloc/free从内存中申请空间,会导致内存碎片问题,内存池直接申请大块内存就减少了内存碎片。通常申请内存都是通过new/delete、malloc/free接口直接从内存的堆区申请一块内存,释放也是直接释放到堆中。频繁的申请和释放必然消耗大量时间,降低程序的运行效率。例如:假设每个链表的节点大小为16字节,当链表需要经常插入节点时,必然就需要频繁的内存申请操纵,每次从堆中申请16个字节都要一定的时间开销,释放内存也需要时间开销。使用内存池,我们可以直接从内存中申请“一批节点”,当程序需要内存时不用直接去堆中申请,直接将预先申请好的内存分配给程序。频繁的从内存中申请小块内存会导致内存碎片问题。内存碎片分为内碎片和外碎片两种。1)外碎片外碎片也就是我们常说的内存碎片。例如:我们每次从内存中申请一块16字节大小的内存,内存中就会存在很多16个字节大小的块,当该内存释放时就可能造成内存碎片,如下图:内存中空闲内存大小为88字节,但是我们能申请的最大内存块为21字节。2)内碎片内碎片是指已经分配出去的内存中存在的未使用的小块内存。内存池技术虽然解决了内存随便但是又造成了内碎片问题,内碎片不可避免但是可以通过程序的优化减少内存内碎片。例如:实际需要是申请10byte的内存,定长内存池可能会进行内存对齐,一次性分配了16个字节的内存,多余的6字节实际并未使用,这6字节就是内存内碎片。1)最最最最“简单”的内存池做一个链表,指向空闲的内存。分配就是从链表中取出来一块返回pop,释放就是将内存在push到链表中。需要做好归并,标记和保护,防止内存二次释放问题。2)定长内存池实现一个FreeList类,它的本质是一个链表,节点是一块固定大小的内存,采用头插和头删的方式申请释放内存。每个固定内存分配器里面有两个链表:OpenList用于存储未分配的空闲内存对象(FreeList对象),CloseList用于存储已经分配的内存对象。分配内存就是从IOpenLsit中取出一个对象给程序,释放内存就是将对象push到CloseList里。当内存不够时,OpenList申请一个大块内存在切割成固定的长度大小的小块内存。3)C++STL库中的内存池定长内存池存在的问题就是只能申请固定长度的内存,而实际中我们需要申请的内存大小可能是不管固定,在C++STL库中,采用哈希表和定长内存池结合的方式实现了一个内存池。具体如下构造多个定长内存池,以一个固定的对齐数进行对齐(例如以8字节进行对齐),第一个定长内存池的内存对象大小为8(至少得能保证无论在64位还是32位系统下都可以保存下一个指针类型),第二个内存池对象大小为16…最后一个内存池对象大小为128byte,当申请的内存大小超过128字节时,通过二级空间配置器申请(直接从内存中申请)。构造一个哈希表,将不同大小的内存对象挂在哈希表中。如下图:申请内存:加入要申请的内存大小为8字节直接在index = 0处分配一块内存,当然申请的内存小于8字节时也会直接分配8字节的内存。当Free_list[index]为nullptr时从内存中申请一块内存,切割成固定大小‘挂在”Free_list[index]位置。释放内存:根据内存对象大小,计算index在插入到哈希表中的index位置。两个链表,RequestMemory和ReleaseMemory。RequestMemory链表存储的是使用new或者malloc从物理内存申请的还没有被使用的内存块,是一个个的memNode节点。ReleaseMemory链表存储 香港云主机的是使用完释放回来的固定大小的内存块。先在ReleaseMemory找,如果有内存则直接pop使用ReleaseMemory为nullptr时,在RequestMemory中找。RequestMemory的头节点表示的是新申请的,申请内存时只需要在头结点中找,判断头结点的useCount和sumCount是否相等。当useCount等于sumCount时表示已经用完了,就需要去物理内存中申请,否则直接从表头push一块。去物理内存申请内存时,申请的大小是上一次申请内存块大小的二倍,并将申请的内存块push到RequestMemory头部。
释放内存时,直接将要释放的内存push到ReleaseMemory的头部即可。blockNode表示一个个新申请的内存块,用一个结构体进行管理。blockNode成员如下:void* _memory:表示新申请的内存块的首地址BlockNode * _next:存储next节点_objNum:内存块对象的个数注意:blockNode的大小每次都是上一次的二倍,是一个质数增长,因此应该设置一个上限,当到达一定大小后进行线性增长。这里规定,最大内存块的大小为100000*sizeof(T),T表示的是申请的节点类型。这里的单个对象指的ReleaseMemory的节点大小,当用户申请的内存大小sizeof(T)小于sizeof(T*)时,为了能够将该对象链接到ReleaseMemory中,应该按照T*进行分配。分别使用malloc/free、new/delete、memPool申请和释放110000个内存,时间如下:关于“C++内存池如何实现”这篇文章的内容就介绍到这里,感谢各位的阅读!相信大家对“C++内存池如何实现”知识都有一定的了解,大家如果还想学习更多知识,欢迎关注开发云行业资讯频道。

相关推荐: Win8开机出现错误C00000022怎么解决

本篇内容主要讲解“Win8开机出现错误C00000022怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Win8开机出现错误C00000022怎么解决”吧!解决方法:一、重启电脑,接着按住 Shift +F8…

免责声明:本站发布的图片视频文字,以转载和分享为主,文章观点不代表本站立场,本站不承担相关法律责任;如果涉及侵权请联系邮箱:360163164@qq.com举报,并提供相关证据,经查实将立刻删除涉嫌侵权内容。

(0)
打赏 微信扫一扫 微信扫一扫
上一篇 07/14 15:47
下一篇 07/14 15:47

相关推荐