内存泄漏,开发C/C++的程序员再熟悉不过了,用一场恶梦来形容它一点也不为过。
不巧,我就碰到了这样的一场恶梦,我在移植一款手机游戏上遇到了这样的问题,当然原来的游戏代码并不是我写的,是谁写的我也不知道,但是确实出现了内存泄漏的问题。内存泄漏的字节并不多,但是积累起来就要命了,而且是在手机上,内存并不富裕。更可怕的是这个问题几乎无从下手。
这是个益智类游戏,是一个3个球成三角就可以消掉的游戏,游戏代码中用了很多结构体和链表,树等数据结构,我根本无法知道,代码中分配的内存是在哪里释放,而且我也不知道这个地方该不该释放,是否还有别的指针指向它。时间不允许我再过多的研究代码的细节,我只能硬着头皮给这个程序打上一个“补丁”了。
这个代码是使用C语言写的,下面列出部分的代码以供参考。
首先我定义了一个链表的节点
typedef struct _TestMem
{
U8 *m_pMemD;//保存分配的地址指针
struct _TestMem *m_pNext;
}TestMem;
并定义了如下的两个变量
TestMem g_Mem;
TestMem *g_pLast;//指向链表的最后一个节点
接下来重写了内存分配很内存回收的函数
void* MALLOC_Ex(uint32 dwSize)
{
void *pVoid = MALLOC(dwSize);
if(g_pLast)
{
g_pLast->m_pNext = (TestMem*)MALLOC(sizeof(TestMem));
g_pLast = g_pLast->m_pNext;
g_pLast->m_pMemD = pVoid;
g_pLast->m_pNext = NULL;
}
return pVoid;
}
void FREE_Ex(void *po)
{
TestMem *pMid;
TestMem *pDel;
pMid = &g_Mem;
while(pMid->m_pNext)
{
pDel = pMid->m_pNext;
if(pDel->m_pMemD == po)
{
if(g_pLast == pDel)g_pLast = pMid;
pMid->m_pNext = pDel->m_pNext;
FREE(pDel);
break;
}
pMid = pMid->m_pNext;
}
FREE(po);
}
使用这两个函数替换原来代码中原有的函数,当然只是替换相关的函数
最后定义初始化和回收的函数
void InitTestMem()
{
g_Mem.m_pMemD = NULL;
g_Mem.m_pNext = NULL;
g_pLast = &g_Mem;
}
void ReleaseTestMem()
{
TestMem *pMid;
TestMem *pDel;
pMid = g_Mem.m_pNext;
while(pMid)
{
if(pMid->m_pMemD)FREE(pMid->m_pMemD);
pDel = pMid;
pMid = pMid->m_pNext;
FREE(pDel);
}
InitTestMem();
}
把InitTestMem函数放到游戏的初始化部分,ReleaseTestMem函数放到原有代码的释放结构体内存的地方(也就是通过当前关,Gameover的地方),用来释放没有释放的内存,也就是那些内存泄漏的部分。
这就基本完成了这个补丁。
但是还有个问题,就是如果玩家始终没有过关或Gameover的话,那么就可能无法调用ReleaseTestMem函数,那么内存也会一直泄漏下去,直到消耗掉所有的内存。因此这里我又添加了一段代码
void AutoDelMem()
{
U32 mem;
mem = 返回当前的FREE内存
if(mem <= 20)//当前内存小于20时释放一部分泄漏内存
{
int count;
TestMem *pMid;
TestMem *pDel;
pMid = g_Mem.m_pNext;
count = 100;//100可根据具体的情况来调整,因为游戏在玩一段时间后,内存泄漏了很多了,这样就可以安全的释放最先泄漏的一部分内存,这里存在一定的风险,不过,还好这个游戏正好符合这个条件
while(count > 0 && pMid)
{
if(pMid->m_pMemD)FREE(pMid->m_pMemD);
pDel = pMid;
pMid = pMid->m_pNext;
FREE(pDel);
--count;
}
g_Mem.m_pNext = pMid;
if(!pMid)g_pLast = &g_Mem;
}
}
使用AutoDelMem函数定期的检测内存,这样就有效解决了因为内存泄漏给游戏带来灾难性的后果了。
这个补丁真是我迫不得已才使用的,现在把它共享给大家,希望能对大家有所帮助。
如果大家有什么意见和建议请告诉我。谢谢
不巧,我就碰到了这样的一场恶梦,我在移植一款手机游戏上遇到了这样的问题,当然原来的游戏代码并不是我写的,是谁写的我也不知道,但是确实出现了内存泄漏的问题。内存泄漏的字节并不多,但是积累起来就要命了,而且是在手机上,内存并不富裕。更可怕的是这个问题几乎无从下手。
这是个益智类游戏,是一个3个球成三角就可以消掉的游戏,游戏代码中用了很多结构体和链表,树等数据结构,我根本无法知道,代码中分配的内存是在哪里释放,而且我也不知道这个地方该不该释放,是否还有别的指针指向它。时间不允许我再过多的研究代码的细节,我只能硬着头皮给这个程序打上一个“补丁”了。
这个代码是使用C语言写的,下面列出部分的代码以供参考。
首先我定义了一个链表的节点
typedef struct _TestMem
{
U8 *m_pMemD;//保存分配的地址指针
struct _TestMem *m_pNext;
}TestMem;
并定义了如下的两个变量
TestMem g_Mem;
TestMem *g_pLast;//指向链表的最后一个节点
接下来重写了内存分配很内存回收的函数
void* MALLOC_Ex(uint32 dwSize)
{
void *pVoid = MALLOC(dwSize);
if(g_pLast)
{
g_pLast->m_pNext = (TestMem*)MALLOC(sizeof(TestMem));
g_pLast = g_pLast->m_pNext;
g_pLast->m_pMemD = pVoid;
g_pLast->m_pNext = NULL;
}
return pVoid;
}
void FREE_Ex(void *po)
{
TestMem *pMid;
TestMem *pDel;
pMid = &g_Mem;
while(pMid->m_pNext)
{
pDel = pMid->m_pNext;
if(pDel->m_pMemD == po)
{
if(g_pLast == pDel)g_pLast = pMid;
pMid->m_pNext = pDel->m_pNext;
FREE(pDel);
break;
}
pMid = pMid->m_pNext;
}
FREE(po);
}
使用这两个函数替换原来代码中原有的函数,当然只是替换相关的函数
最后定义初始化和回收的函数
void InitTestMem()
{
g_Mem.m_pMemD = NULL;
g_Mem.m_pNext = NULL;
g_pLast = &g_Mem;
}
void ReleaseTestMem()
{
TestMem *pMid;
TestMem *pDel;
pMid = g_Mem.m_pNext;
while(pMid)
{
if(pMid->m_pMemD)FREE(pMid->m_pMemD);
pDel = pMid;
pMid = pMid->m_pNext;
FREE(pDel);
}
InitTestMem();
}
把InitTestMem函数放到游戏的初始化部分,ReleaseTestMem函数放到原有代码的释放结构体内存的地方(也就是通过当前关,Gameover的地方),用来释放没有释放的内存,也就是那些内存泄漏的部分。
这就基本完成了这个补丁。
但是还有个问题,就是如果玩家始终没有过关或Gameover的话,那么就可能无法调用ReleaseTestMem函数,那么内存也会一直泄漏下去,直到消耗掉所有的内存。因此这里我又添加了一段代码
void AutoDelMem()
{
U32 mem;
mem = 返回当前的FREE内存
if(mem <= 20)//当前内存小于20时释放一部分泄漏内存
{
int count;
TestMem *pMid;
TestMem *pDel;
pMid = g_Mem.m_pNext;
count = 100;//100可根据具体的情况来调整,因为游戏在玩一段时间后,内存泄漏了很多了,这样就可以安全的释放最先泄漏的一部分内存,这里存在一定的风险,不过,还好这个游戏正好符合这个条件
while(count > 0 && pMid)
{
if(pMid->m_pMemD)FREE(pMid->m_pMemD);
pDel = pMid;
pMid = pMid->m_pNext;
FREE(pDel);
--count;
}
g_Mem.m_pNext = pMid;
if(!pMid)g_pLast = &g_Mem;
}
}
使用AutoDelMem函数定期的检测内存,这样就有效解决了因为内存泄漏给游戏带来灾难性的后果了。
这个补丁真是我迫不得已才使用的,现在把它共享给大家,希望能对大家有所帮助。
如果大家有什么意见和建议请告诉我。谢谢