今天开始重构一个DEMO工程,在整理代码时发现之前写过的一个内存

管理与内存检测代码,再此梳理一番加深下印象。

 

一.内存检测模块的作用:

 

在做项目时经常出现内存泄漏内存访问越界等情况,当工程比较大时排

查起来会相对比较困难。这个内存管理模块的作用就是管理内存分配和

使用并在DEBUG环境下统计内存使用违规情况。

 

 

二.内存管理模块的基本原理:

 

该内存管理模块的设计思路是:在用户请求分配内存时记录请求分配该

内存的代码环境信息(如:在哪个文件中的哪一行请求分配多大内存等),

内存分配的形式采用内存池与内存块相结合的方式,并在释放内存时检测

该块内存是否被写坏(是否有被越界使用)或者该内存释放未被释放形成了

内存泄漏等,记录内存使用情况供给用户分析定位异常情况。

注: 根据一般内存使用情况,用户对小块内存的请求/释放较为频繁对连续

的大块内存使用较少或者频率较低,为了提高内存分配的效率可以将频繁使

用的小块内存使用内存池的方式管理,事先分配一块固定大小的内存池每次

用户请求都从中划分一块(具体使用方法下面会详细记录),对交大的内存块(如

一次请求分配10M连续大小的内存空间)则用内存块方式来管理(具体使用方法下

面会详细记录)。

 

三.内存管理模块的基本结构:

 

 

 

 

1. Memory_Info类;

该类用于保存内存分配信息情况,用于检测内存泄漏及内存访问越界记录用户使用内存信息等。
structMemory_Info
{
char sFile[64]; // 保存调用内存分配函数的代码文件

unsigned int nLine;//保存调用内存分配函数的代码行
unsigned int nUsed; // 用户请求分配内存大小
unsigned int nSize; // 内存池中标准格式大小
unsigned int nCount; // 用户请求分配个数(数组)
testcode sCode;// 用于检测内存越界的填充码(可自定义为0x01234567等)
union
{
Memory_Info* next; // 未分配空间时指向下一区域
char data[4]; // 分配空间时指向真正使用内存区域
};
};




2. Memory_Pool类;


该类在创建时会记录自己是多大规格内存的缓冲区(如用来存储4字节的缓冲区还是用来存
16字节的缓冲区),这样做的好处是字节对齐,事先分配固定大小的内存(在DEBUG环境
下分配增加了环境信息的每个缓冲区单元大小为存储字节数(如4字节)+
sizeof(Memory_Info),RELEASE下可直接分配缓冲区大小字节)。同时用一个链表来管理
这些区域,当用户请求该大小内存时则只需要从链表中取出一块内存给用户使用,释放时
也并不直接free而是放回当链表中。减少了动态开辟内存的次数。


class Memory_Pool
{

public:
Memory_Pool();
~Memory_Pool();



void* allocate( size_t size, const void* file = 0, unsigned int line = 0 );
void free(void* p);

size_t m_size;
size_t m_actual_size;
Memory_Info* m_pHeader;

};




注: 在释放内存时会检测内存是否访问越界,检测方式也很简单就是判断Memory_Info
数据块的sCode是否发生变化,如果发生了变化则说明有发生过访问越界,输出错误提
示信息。Memory_Pool的基本结构是链表,通过动态添加/移出链表节点实现对用户的
内存释放和回收记录内存使用情况。




3. Memory_List类;



与Memory_Pool类类似,只是Memory_List得管理方式是双向链表,并且与内存池不同
它不会规定分配内存的规格格式。


4. MemoryManager类:


管理类对外提供分配内存的接口,管理了一个内存池数组(包含多个大小内存池如4字
节内存池 8字节内存池 16字节内存池... )和一个内存列表(用于管理大块连续内存
如大于1M的连续内存),根据用户请求内存大小采用不同方式(内存池/内存列表)分配,
记录内存使用情况等。在程序结束时输出内存使用异常情况。
注: 内存分配时的环境信息如函数,代码文件等可以通过调用MemoryManager::
Allocate()接口时传入,具体方法参见 5.接口对接.


5. 接口对接:


为了是用户无差别使用new delete等分配内存方式,可以采用重载new delete运算符
的方式直接调用MemoryManager::Allocate(),或者用宏定义的方式定义。



void*operator new ( size_t nSize, const char* p, size_t n )
{
MemoryManager::Allocate( nSize, pFile, nLine );
}



#definenew new( __FILE__, __LINE__ )


注: 经过重载new后用户可以正常使用new来分配内存而实际new经替换为我们自定义的
内存管理方式来管理。




四.不足:


与正常内存相比,用管理器管理会额外增加内存空间,且在大量分配大块连续内存数据
时的性能也会稍稍有些影响。

锐亚教育

锐亚教育,游戏开发论坛|游戏制作人|游戏策划|游戏开发|独立游戏|游戏产业|游戏研发|游戏运营| unity|unity3d|unity3d官网|unity3d 教程|金融帝国3|8k8k8k|mcafee8.5i|游戏蛮牛|蛮牛 unity|蛮牛