使用內(nèi)存池管理對(duì)象內(nèi)存

在需要頻繁地 new/delete 對(duì)象時(shí),很容易造成對(duì)象分配慢、內(nèi)存碎片的產(chǎn)生。為提升應(yīng)用程序在分配對(duì)象內(nèi)存的效率,可以使用內(nèi)存池管理對(duì)象內(nèi)存的分配和釋放。
作者按以下方式實(shí)現(xiàn):

  • 編寫模板類 CMemoryPool, 為每個(gè)類創(chuàng)建一個(gè)靜態(tài)的內(nèi)存池對(duì)象
  • 內(nèi)存池類按大塊向系統(tǒng)申請(qǐng)內(nèi)存,將內(nèi)存以靜態(tài)雙向鏈表進(jìn)行關(guān)聯(lián),形成空閑鏈表
  • 分配類對(duì)象內(nèi)存時(shí),從空閑鏈表淘汰一個(gè)元素,并將此結(jié)點(diǎn)添加到已分配的雙向鏈表中
  • 在內(nèi)存池中將分配過的內(nèi)存結(jié)點(diǎn)使用雙向鏈表關(guān)聯(lián),同時(shí)實(shí)現(xiàn)應(yīng)用程序退出后內(nèi)存泄漏自動(dòng)檢查
  • 釋放類對(duì)象內(nèi)存時(shí),從已分配的雙向鏈表中移除結(jié)點(diǎn)元素,并歸還給空閑鏈表中
  • 提供宏為類添加內(nèi)存池的靜態(tài)成員對(duì)象,并重載類的 operator new 和 operator delete 運(yùn)算符
  • 不允許構(gòu)造對(duì)象數(shù)組(此內(nèi)存池內(nèi)不支持動(dòng)態(tài)創(chuàng)建對(duì)象數(shù)組)
  • 在使用時(shí),只需要在類定義中加入 DECLARE_MEMORY_POOL 宏聲明,在實(shí)現(xiàn)文件中加入 IMPLEMENT_MEMORY_POOL 宏實(shí)現(xiàn)
MemoryPool.h 文件中實(shí)現(xiàn)了模板類 CMemoryPool, 代碼如下
#ifndef ___MEMORY__POOL__20141227___
#define ___MEMORY__POOL__20141227___
 
#include "OSType.h"
#include "Mutex.h"
#include <list>
#include <string>
#include <stdio.h>
#include <stdlib.h>
 
#define DECLARE_MEMORY_POOL(className) \
    private: \
        static CMemoryPool<className> m_memoryPool ## className; \
    public: \
        void* operator new(size_t size) \
        { \
            return m_memoryPool ## className.Allocate(); \
        } \
        void operator delete(void *pBuffer) \
        { \
            m_memoryPool ## className.Free(pBuffer); \
        } \
        void* operator new[](size_t size); \
        void operator delete[](void *pBuffer); \
        private:
 
#define IMPLEMENT_MEMORY_POOL(className) \
    CMemoryPool<className> className::m_memoryPool ## className(#className);
 
template <typename T>
struct SMemoryPoolNode
{
    T                       obj;
    SMemoryPoolNode*        pPrev;
    SMemoryPoolNode*        pNext;
};
 
// 定義內(nèi)存池塊的大小
#define MEMORY_POOL_BLOCK_SIZE 1048576LL
 
template <typename T>
class CMemoryPool
{
public:
    CMemoryPool(LPCSTR lpszClassName);
    ~CMemoryPool();
 
public:
    void* Allocate();
    void Free(void *pBuffer);
 
private:
    Bool NeedMoreBlock();
 
private:
    std::string                     m_strClassName;
    size_t                          m_nBlockSize;
    std::list<void *>                m_lstBlockList;
 
    SMemoryPoolNode<T>*               m_pFreeList;
    SMemoryPoolNode<T>*               m_pUsedList;
    CMutex                          m_lock;
};
 
template <typename T>
CMemoryPool<T>::CMemoryPool(LPCSTR lpszClassName) : m_strClassName(lpszClassName)
{
    m_nBlockSize = MEMORY_POOL_BLOCK_SIZE;
    m_nBlockSize = m_nBlockSize / sizeof(SMemoryPoolNode<T>) * sizeof(SMemoryPoolNode<T>);
    if (sizeof(SMemoryPoolNode<T>) > m_nBlockSize)
    {
        m_nBlockSize = 10 * sizeof(SMemoryPoolNode<T>);
    }
 
    m_pFreeList = NULL;
    m_pUsedList = NULL;
 
    NeedMoreBlock();
}
 
template <typename T>
CMemoryPool<T>::~CMemoryPool()
{
    // 打印出未釋放的內(nèi)存
    if (m_pUsedList != NULL)
    {
        SMemoryPoolNode<T> *ptr = m_pUsedList;
        while (ptr)
        {
            fprintf(stderr, "class %s: Memory leak found at %p with %lu B\n", m_strClassName.c_str(), ptr, sizeof(T));
            ptr = ptr->pNext;
        }
    }
 
    for (std::list<void *>::const_iterator it = m_lstBlockList.begin(); it != m_lstBlockList.end(); ++it)
    {
        free(*it);
    }
}
 
template <typename T>
void* CMemoryPool<T>::Allocate()
{
    CMutexLocker lock(&m_lock);
 
    if (NULL == m_pFreeList)
    {
        if (!NeedMoreBlock())
        {
            return NULL;
        }
    }
 
    SMemoryPoolNode<T> *pNode = m_pFreeList;
    m_pFreeList = m_pFreeList->pNext;
 
    if (m_pFreeList != NULL)
    {
        m_pFreeList->pPrev = NULL;
    }
 
    SMemoryPoolNode<T> *pLastUsedHead = m_pUsedList;
    m_pUsedList = pNode;
    m_pUsedList->pNext = pLastUsedHead;
    if (pLastUsedHead != NULL)
    {
        pLastUsedHead->pPrev = m_pUsedList;
    }
 
    return &pNode->obj;
}
 
template <typename T>
void CMemoryPool<T>::Free(void *pBuffer)
{
    CMutexLocker lock(&m_lock);
 
    SMemoryPoolNode<T> *pNode = (SMemoryPoolNode<T> *)pBuffer;
    if (pNode->pPrev != NULL)
    {
        pNode->pPrev->pNext = pNode->pNext;
         
        if (pNode->pNext != NULL)
        {
            pNode->pNext->pPrev = pNode->pPrev;
        }
    }
    else
    {
        m_pUsedList = pNode->pNext;
        if (m_pUsedList != NULL)
        {
            m_pUsedList->pPrev = NULL;
        }
    }
 
    pNode->pPrev = NULL;
    SMemoryPoolNode<T> *pLastFreeHead = m_pFreeList;
    m_pFreeList = pNode;
    m_pFreeList->pNext = pLastFreeHead;
    if (pLastFreeHead != NULL)
    {
        pLastFreeHead->pPrev = m_pFreeList;
    }
}
 
template <typename T>
Bool CMemoryPool<T>::NeedMoreBlock()
{
    void *ptr = malloc(m_nBlockSize);
    if (NULL == ptr)
    {
        return False;
    }
 
    Int32 nNodeCount = m_nBlockSize / sizeof(SMemoryPoolNode<T>);
    SMemoryPoolNode<T> *pLastNode = (SMemoryPoolNode<T> *)ptr;
 
    m_pFreeList = pLastNode;
    pLastNode->pPrev = NULL;
    pLastNode->pNext = NULL;
 
    for (Int32 i = 1; i < nNodeCount; ++i)
    {
        SMemoryPoolNode<T> *pNext = (SMemoryPoolNode<T> *)ptr + i;
        pNext->pPrev = pLastNode;
        pNext->pNext = NULL;
        pLastNode->pNext = pNext;
        pLastNode = pNext;
    }
 
    m_lstBlockList.push_back(ptr);
    return True;
}
 
#endif

以上包含了 OSTypes.h, 其包含了類型自定義,同時(shí)為了在多線程中使用,使用了互斥鎖,并進(jìn)行了封裝。這二處的代碼略之。

測(cè)試代碼
#include <iostream>
#include <stdio.h>
#include "MemoryPool.h"
using namespace std;
 
class CMemoryTest
{
    DECLARE_MEMORY_POOL(CMemoryTest)
 
public:
    CMemoryTest()
    {
    }
 
    ~CMemoryTest()
    {
    }
 
private:
    char m_szBuff[100];
};
 
IMPLEMENT_MEMORY_POOL(CMemoryTest)
 
Int32 main()
{
    CMemoryTest *pTest1 = new CMemoryTest();
    CMemoryTest *pTest2 = new CMemoryTest();
 
    delete pTest1;
    delete pTest2;
 
    pTest1 = new CMemoryTest();
    pTest2 = new CMemoryTest();
     
//  delete pTest1;
//  delete pTest2;
 
    return 0;
}

測(cè)試結(jié)果如下:

class CMemoryTest: Memory leak found at 0x7f5d62518010 with 100 B
class CMemoryTest: Memory leak found at 0x7f5d62617f88 with 100 B

說明:

  • 在定義 DECLARE_MEMORY_POOL 宏時(shí),使用 ## 將類名拼接到 m_memoryPool 的后面形成一個(gè)對(duì)象名稱;
  • 在定義 IMPLEMENT_MEMORY_POOL 宏時(shí),為了給 CMemoryPool 的構(gòu)造函數(shù)傳遞類名字符串的參數(shù),使用 # 將宏參數(shù)轉(zhuǎn)換為字符串,在應(yīng)用程序退出時(shí),使用了內(nèi)存池的類的 m_memoryPool ## className 對(duì)象會(huì)被銷毀,在其析構(gòu)函數(shù)中,會(huì)將未釋放的內(nèi)存打印出來,包括類名、內(nèi)存地址及泄漏的字節(jié)數(shù),非常便于調(diào)試內(nèi)存泄漏。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,664評(píng)論 1 32
  • 內(nèi)存是計(jì)算機(jī)非常關(guān)鍵的部件之一,是暫時(shí)存儲(chǔ)程序以及數(shù)據(jù)的空間,CPU只有有限的寄存器可以用于 存儲(chǔ)計(jì)算數(shù)據(jù),而大部...
    dreamer_lk閱讀 1,628評(píng)論 2 10
  • Java8張圖 11、字符串不變性 12、equals()方法、hashCode()方法的區(qū)別 13、...
    Miley_MOJIE閱讀 3,899評(píng)論 0 11
  • 內(nèi)存管理 簡(jiǎn)述OC中內(nèi)存管理機(jī)制。與retain配對(duì)使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,081評(píng)論 1 16
  • 嵌入式系統(tǒng)的內(nèi)存管理 姓名:張猛 引用自:http://blog.csdn.net/baskmmu/article...
    oliverabc閱讀 2,206評(píng)論 0 0

友情鏈接更多精彩內(nèi)容