給內存泄漏打個補丁

內存泄漏,開發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函數定期的檢測內存,這樣就有效解決了因爲內存泄漏給遊戲帶來災難性的後果了。

這個補丁真是我迫不得已才使用的,現在把它共享給大家,希望能對大家有所幫助。
如果大家有什麼意見和建議請告訴我。謝謝 

2007年05月22日 22:21:00

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