代码很简单总共两个文件分别是.h和.cpp ,已经重载了new 和delete,所以使用者只需要把代码包含到工程里就可以了,不用写一行代码即可使用。
为什么要自己管理内存分配?
第一,首先是效率,频繁的调用系统的new 和 delete 效率稍微有点低。
第二,因为内存分配我们自己控制,我们可以一定程度的控制内存碎片的整理,这样程序跑的时间长不用担心因为内存碎片的问题挂掉。
第三,对当前程序使用的内存,可以比较方便的做各种统计。
代码实现思路:
程序启动的时候,向系统申请一块大的内存,之后程序里需要用到的内存,我们都从这块内存内进行分配,当程序释放内存,我们也回收到这块内存之内,而不是真的交给系统。总之就是程序后续的申请内存,释放内存,都不会直接跟系统打交道。而是跟我们的内存管理类打交道。
CMemory 这个类就是我们说的 一开始向系统申请的大内存。
stMemChunck 表示一小块内存,用于表示用户new出来的内存块,当用户delete 对象的时候,也是一块stMemChunck 。
CMemoryMgr 内存块的管理者,管理多块CMemory ,当程序运行中 ,一开始申请的一大块内存有可能用完的,所以需要再申请一块,CMemoryMgr 主要就是协调这个事情的,
程序运行流程:
一开始CMemory 里面只有一个stMemChunck ,它的大小就是整个内存的大小,当在程序里面调用一次 new 某个对象的时候,stMemChunck 会产生两个,一个返回出去给程序使用,一块继续保留。正在被使用的stMemChunck 我们没有记录。 当程序里调用一次delete 某个对象的时候,CMemory 会回收内存,形成stMemChunck , 作为链表的一个节点,按照内存地址的顺序,加到链表上的。(所有被回收的stMemChunck 组成一个链表,程序启动的时候 就一个节点)。加入链表以后,我们会根据加入节点的地址以及大小判断他是否可以与它左右两个节点进行合并,碎片整理。stMemChunck 按照地址形成链表的目的就是为了做碎片整理。
策略:
在代码里面,大家可以看到 size_t addChunck(stMemChunckPtr pChucnk,size_t beginIdx, size_t endIdx); size_t removeChunck(stMemChunckPtr pChucnk,size_t beginIdx, size_t endIdx); 这两个函数,这个主要是为了维护一个数组,把
stMemChunck 按照其大小进行排序。 上面说了,把stMemChunck 按地址形成链表是为了最碎片整理。那么按照其大小排序 其实就是了 快速查找匹配请求内存大小的内存。举个例子吧,我们要new 一个 对象,对象大小是 20 个字节,这个时候,CMemory 里有很多多个stMemChunck ,那么改怎么选呢?比20字节大的stMemChunck 有很多,100 字节的可用,50 字节的也可以用,20个字节的也可以用。这个时候,我们是不是应该选择20个字节的呢? 为了快速找到合适的stMemChunck 所以我们就维护了一个大小排序。
最后,代码只是抛砖引玉。如有什么疑问和bug请大家告诉我!