PlanetEngine中的内存管理

PlanetEngine中内存管理是比较传统的,主要就是这些:重载new、delete、引用计数、智能指针。

#ifndef EP3DCORE_MEM_MANAGE
    #define EP3DNew new
    #define EP3DDelete delete
#else
    class  EP3DEXPORT Memory
   {
    public:
            static void* Allocate(size_t uiSize, char* acFile, uint uiLine, bool bIsArray);
            static void Deallocate(char* pvAddr, bool bIsArray);
    …
    }

    #define  EP3DNew new(__FILE__, __LINE__)
    #define  EP3DDelete delete
    void* operator new (size_t uiSize);
    void* operator new[] (size_t uiSize);
    void* operator new (size_t uiSize, char* acFile, unsigned int uiLine);
    void* operator new[] (size_t uiSize, char* acFile, unsigned int uiLine);
    void operator delete (void* pvAddr);
    void operator delete[] (void* pvAddr);
    void operator delete (void* pvAddr, char* acFile, unsigned int uiLine);
    void operator delete[] (void* pvAddr, char* acFile, unsigned int uiLine);
#endif

通过宏控制,我们可以启动或关闭内存管理,全局的几个动态内存管理函数通过class Memory来分配跟踪内存的分配,且用户只能通过EP3DNew、EP3DDelete来实现内存管理;当开发人员在Debug模式下开发时开启内存管理EP3DNew、EP3DDelete的内存分配将由class Memory实现,当发布release版本时EP3DNew、EP3DDelete将编译为标准版本的new和delete;

除此外,class Memory还提供了一些额外的内存监控变量用来监控内存的使用情况,方便开发中进行内存泄露检测和性能优化;

class  EP3DEXPORT Memory
{
    public:
            static void* Allocate(size_t uiSize, char* acFile, uint uiLine, bool bIsArray);
            static void Deallocate(char* pvAddr, bool bIsArray);

            static size_t GetNumNewCalls() { return ms_uiNumNewCalls; }
            static size_t GetNumDeletetCalls() { return ms_uiNumDeleteCalls; }
            static size_t GetNumBlocks() { return ms_uiNumBlocks; }
            static size_t GetNumBytes() { return ms_uiNumBytes; }
            static size_t GetMaxAllocatedBytes() { return ms_uiMaxAllocatedBytes; }
            static size_t GetMaxBlockSize() { return ms_uiMaxBlockSize; }
            static size_t GetHistogram(int i) { return ms_auiHistogram[i]; }

            //输出结果           
            static void GenerateReportToLogFile(const char* acFilename);
            static void GenerateReportToDebugWindow();
    private:
            static size_t ms_uiNumNewCalls;
            static size_t ms_uiNumDeleteCalls;
            static size_t ms_uiNumBlocks;
            static size_t ms_uiNumBytes;
            static size_t ms_uiMaxAllocatedBytes;
            static size_t ms_uiMaxBlockSize;
            static size_t ms_auiHistogram[32];
    …
}

在对象生命周期管理方面,是采用简单的引用计数来控制的,继承分支如下:

image

 

 

 

 

 

 

 

 

 

 

 

RefCounter就是基础的计数器类,大部分对象从此类派生,简单易用可靠,但是缺点是明显的就是通用性比较差,同时对象大量被使用时,过多引用计数将带来一些性能损耗。

从RefCounter派生的类同时还具有一些使用上的限制:
1)派生类不应该在栈上创建对象,因为栈对象的生命周期是由c++来管理的(它们会在离开当前作用域时被销毁,从而绕过引用计数管理机制);
2)派生类不能进行拷贝,这样会造成引用计数器机制混乱;
3)派生类必须要有一虚析构函数;
4)派生类只有一个默认的构造函数;

class EP3DEXPORT RefCounter
{
public:
    RefCounter(void);
    virtual ~RefCounter(void);
    uint AddRef(void);
    uint Release(void);
    uint GetReferenceCount(void);
    uint GetTotalReferenceCount(void);

private:
    uint m_uiRefCount;
    static uint ms_uiObjects;
};

PlanetEngine使用一个模板智能指针来处理RefCounter对象的生命周期;Pointer<>隐藏了引用计数的实现细节,且应该一直指向RefCounter的派生对象;使用Poiner<>的好处:
1)访问一个空指针时,会给断言;
2)不需要手动调用AddRef()和Release();
3)可以在STL容器类里很好的工作,你不需要考虑手动去释放对象,智能指针会自动管理这一切.
4)不用考虑指针的所属,因为这一切智能指针为你管理了;

当然缺点也是明显的:
1)引用和解除引用会带来计数器的运算,解除引用时还会带来断言的检查,这会带来一些微不足道的性能损耗;
2)因为只有当计数为0时才释放对象,这样会带来对象存在超出它的预订时间,容易带来BUG,不过在程序退出时,未被释放的对象抛出断言会提醒你。

给出实现:
template<class T>
class Pointer
{
    public:
        Pointer(T* pObject = (T*)0)
        {
            m_pObject = pObject;
            if (m_pObject)
                m_pObject->AddRef();
        }

        Pointer(const Pointer<T>& ptr)
        {
            m_pObject = ptr.m_pObject;
            if (m_pObject)
                m_pObject->AddRef();
        }

        ~Pointer()
        {
            if (m_pObject)
                m_pObject->Release();
        }

        operator T* () const
        {
            LogAssert(m_pObject);
            return m_pObject;
        }

        T& operator * () const
        {
            LogAssert(m_pObject);
            return *m_pObject;
        }

        T* operator -> () const
        {
            LogAssert(m_pObject);
            return m_pObject;
        }

        Pointer& operator = (const Pointer<T>& ptr)
        {
            if (m_pObject != ptr.m_pObject)
            {
                if (m_pObject)
                    m_pObject->Release();
                m_pObject = ptr.m_pObject;
                if (m_pObject)
                    m_pObject->AddRef();
            }
            return *this;
        }

        Pointer& operator = (T* pObject)
        {
            if (m_pObject != pObject)
            {
                if (m_pObject)
                    m_pObject->Release();
                m_pObject = pObject;
                if (m_pObject)
                    m_pObject->AddRef();
            }
            return *this;
        }

        bool operator == (T* pObject) const
        {
            return (m_pObject == pObject);
        }

        bool operator != (T* pObject) const
        {
            return (m_pObject != pObject);
        }

        bool operator == (const Pointer<T>& ptr) const
        {
            return (m_pObject == ptr.m_pObject);
        }

        bool operator != (const Pointer<T>& ptr) const
        {
            return (m_pObject != ptr.m_pObject);
        }

    protected:
        T* m_pObject;
};

#define  SmartPointer(classname) \
    class classname; \
    typedef Pointer<classname> classname##Ptr;

posted @ 2010-04-11 11:47  繁星  Views(324)  Comments(0Edit  收藏  举报