BREW使用C++及内存检测

很早之前,我第一次接触BREW的时候,他们告诉我说只能用C,那个时候,BREW好像刚出到SDK 2.1,也说不定没出来,后来,我用C的struct来模拟C++的类及Java类。第一次的接触大概持续了不到两个月,第二次的接触却在两年之后,而这次,接触的也大部分是C的代码,通过查看编译器的资料,知道可以对C++进行大部分支持了,而这一次,却持续了3年之久,并且可能还会持续一段不小的时间。
话题扯远了,第二次的时候,看了下别人的C++代码,每个类里面都要重载new,delete,对于类似我这样的懒人实在是不方便,于是就写了个重载全局new,delete等函数的代码,如下所示:

.h

       extern void* operator new( size_t sz );
       extern void operator delete( void* mi );
       extern void* operator new[]( size_t sz );
       extern void operator delete[]( void* mi );
       

.cpp

       /*!
 * @brief 重载new操作符
 * 
 * @param sz 欲分配的内存大小
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new操作符
 */
void* operator new ( size_t sz )
	{
        if( sz == 0 )
            return NULL;
        void* mi = MALLOC( sz );
        return mi;
	}
    /*!
 * @brief 重载delete操作符
 * 
 * @param mi 欲释放的内存地址
 * @return 无
  * @remark
 *
 * 在ARM中如果使用C++,必须重载delete函数
 */
void operator delete( void* mi )
	{
        if( mi == NULL )
            return;
        FREE( mi );
        mi = NULL;
	}
    /*!
 * @brief 重载new[]操作数
 * 
 * @param sz 欲分配内存的大小
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new[]函数
 */
void* operator new[]( size_t sz )
	{
        if( sz == 0 )
            return NULL;
        void* mi = MALLOC( sz );
        return mi;
	}
    /*!
 * @brief 重载delete[]函数
 * 
 * @param mi 欲释放的内存地址
 * @return 无
 * @remark
 *
 * 在ARM中如果使用C++,必须重载delete[]函数
 */
void operator delete[]( void* mi )
	{
        if( mi == NULL )
            return;
        FREE( mi );
        mi = NULL;
	}
       

上面的代码在使用不久,大约不到一周的样子,被我更改了,因为我需要一个可以检测内存泄漏的玩意,于是,就将之前提到的检测内存泄漏的C++版本的代码加入了,大约用了大半年的样子,对BREW程序的测试流程已非常熟悉了,三思之后,制作了内存管理器。在此之后的代码维持了很长时间,直到现在还在使用。
.h文件变成了这个样子:

       /*!
 * @file MemoryAlloc.h
 * @brief 内存分配
 * 
 *  此文件为内存分配并提供简单的内存检测工具。内存检测工具为可以选择的,如果要使用内存检测,则添加#define _DEBUG1。添加#define TEST_MEM可以用来测试程序使用的内存量。如果使用预分配内存管理,则添加#define USE_MEMMANAGER。
 *  需要注意的是,如果使用new Type或者new Type[]的方式,则不会使用预分配内存管理。必须使用new (MEM_TYPE) Type或者new (MEM_TYPE)的方式进行分配。删除内存则不需要进行特殊处理。在程序的AEEApplet之后,必须放置CMemoryManger实例。具体用法可参考例子test_MemoryAlloc
 * @copyright GPL
 * @warning
 *
 * 内存检测仅仅可以在wis平台上使用,ARM平台不可以使用
 */
#ifndef _H_MEMORYALLOC
#define _H_MEMORYALLOC
#include "AEEStdlib.h"


extern void* operator new( size_t sz );
extern void operator delete( void* mi );
extern void* operator new[]( size_t sz );
extern void operator delete[]( void* mi );
extern void* operator new( size_t sz, int atype );
extern void* operator new[]( size_t sz, int atype );

#endif
       

.cpp文件变成了这样:

       #include "MemoryAlloc.h"

#ifdef TEST_MEM
#include "AEEHeap.h"
#include "AEEAppGen.h"
#endif
#ifdef USE_MEMMANGER
#include "MemoryManger.h"
#include "AEEAppGen.h"
#endif
#ifdef _DEBUG1
#include "MemoryLog.h"
MEMORYLOG iMemLog;//!< 全局变量,用于记录指针,在正常情况下仅存这一个变量
#endif


#ifdef TEST_MEM
static int memuse = 0; //!< 程序使用的内存量
static int used = 0; //!< 已经使用的内存量
/*!
 * @class Log
 * @brief 空类,用来在程序结束之后打印出程序使用的内存量
 *
 * @waring
 *
 * 内存检测仅仅可以在wins平台使用,arm平台不可以使用
 * @copyright GPL
 */
class Log{
public:
    /*!
     * @brief 构造函数
     */
	Log()
		{
		}
    /*!
     * @brief 析构函数
     */
	~Log()
		{
		DBGPRINTF("Mem:%d", used );
		}
	};
Log MyLog; //!< 用来在程序结束之后打印程序使用内存量的变量
#endif

/*!
 * @brief 重载new操作符
 * 
 * @param sz 欲分配的内存大小
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new操作符
 */
void* operator new ( size_t sz )
	{
        if( sz == 0 )
            return NULL;
        void* mi = MALLOC( sz );
#ifdef _DEBUG1
        if( !mi )
        {
            DBGPRINTF("out memory");
        }
        else
        {
            MEMSTRUCT* toadd = (MEMSTRUCT*)MALLOC( sizeof( MEMSTRUCT ) );
            toadd->addr = mi;
            toadd->length = sz;
            iMemLog.Add(toadd);
        }
#endif
#ifdef TEST_MEM
        IHeap* pHeap= NULL;
        AEEApplet* pMe = (AEEApplet*)GETAPPINSTANCE();
        ISHELL_CreateInstance( pMe->m_pIShell, AEECLSID_HEAP, ( void** )( & pHeap ) );
        if( memuse == 0 )
        {
            used = memuse =  IHEAP_GetMemStats( pHeap );
        }
        if( IHEAP_GetMemStats( pHeap ) - memuse > used )
        {
            used = IHEAP_GetMemStats( pHeap ) - memuse;
        }
        IHEAP_Release( pHeap );
#endif
        return mi;
	}
/*!
 * @brief 重载delete操作符
 * 
 * @param mi 欲释放的内存地址
 * @return 无
  * @remark
 *
 * 在ARM中如果使用C++,必须重载delete函数
 */
void operator delete( void* mi )
	{
        if( mi == NULL )
            return;
#ifdef USE_MEMMANGER
        CMemoryManger* manger = ( CMemoryManger* )( ( byte* )( GETAPPINSTANCE() ) + sizeof( AEEApplet ) );
        if( manger->MemoryFree( mi ) )
            return;
#endif
#ifdef _DEBUG1
        iMemLog.Sub(mi);
#endif
        FREE( mi );
        mi = NULL;
	}
/*!
 * @brief 重载new[]操作数
 * 
 * @param sz 欲分配内存的大小
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new[]函数
 */
void* operator new[]( size_t sz )
	{
        if( sz == 0 )
            return NULL;
        void* mi = MALLOC( sz );
#ifdef _DEBUG1
        if( !mi )
        {
            DBGPRINTF("our memory");
        }
        else
        {
            MEMSTRUCT* toadd = (MEMSTRUCT*)MALLOC( sizeof( MEMSTRUCT ) );
            toadd->addr = mi;
            toadd->length = sz;
            iMemLog.Add(toadd);
        }
#endif
#ifdef TEST_MEM
        IHeap* pHeap= NULL;
        AEEApplet* pMe = (AEEApplet*)GETAPPINSTANCE();
        ISHELL_CreateInstance( pMe->m_pIShell, AEECLSID_HEAP, ( void** )( & pHeap ) );
        if( memuse == 0 )
        {
            used = memuse =  IHEAP_GetMemStats( pHeap );
        }
        if( IHEAP_GetMemStats( pHeap ) - memuse > used )
        {
            used = IHEAP_GetMemStats( pHeap ) - memuse;
        }
        IHEAP_Release( pHeap );
#endif
        return mi;
	}
/*!
 * @brief 重载delete[]函数
 * 
 * @param mi 欲释放的内存地址
 * @return 无
 * @remark
 *
 * 在ARM中如果使用C++,必须重载delete[]函数
 */
void operator delete[]( void* mi )
	{
        if( mi == NULL )
            return;
#ifdef USE_MEMMANGER
        CMemoryManger* manger = ( CMemoryManger* )( ( byte* )( GETAPPINSTANCE() ) + sizeof( AEEApplet ) );
        if( manger->MemoryFree( mi ) )
            return;
#endif
#ifdef _DEBUG1	
        iMemLog.Sub(mi);
#endif
        FREE( mi );
        mi = NULL;
	}
/*!
 * @brief 重载new操作符
 * 
 * @param sz 欲分配的内存大小
 * @param atype 欲分配的内存的种类
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new操作符
 */
void* operator new( size_t sz, int atype )
{
    if( sz == 0 )
        return NULL;
#ifdef USE_MEMMANGER
    CMemoryManger* manger = ( CMemoryManger* )( ( byte* )( GETAPPINSTANCE() ) + sizeof( AEEApplet ) );
    void* mi = manger->MemoryAlloc( atype, sz );
#else    
    void* mi = MALLOC( sz );
#endif
#ifdef _DEBUG1
        if( !mi )
        {
            DBGPRINTF("out memory");
        }
        else
        {
            MEMSTRUCT* toadd = (MEMSTRUCT*)MALLOC( sizeof( MEMSTRUCT ) );
            toadd->addr = mi;
            toadd->length = sz;
            iMemLog.Add(toadd);
        }
#endif
#ifdef TEST_MEM
        IHeap* pHeap= NULL;
        AEEApplet* pMe = (AEEApplet*)GETAPPINSTANCE();
        ISHELL_CreateInstance( pMe->m_pIShell, AEECLSID_HEAP, ( void** )( & pHeap ) );
        if( memuse == 0 )
        {
            used = memuse =  IHEAP_GetMemStats( pHeap );
        }
        if( IHEAP_GetMemStats( pHeap ) - memuse > used )
        {
            used = IHEAP_GetMemStats( pHeap ) - memuse;
        }
        IHEAP_Release( pHeap );
#endif
        return mi;
}
/*!
 * @brief 重载new[]操作符
 * 
 * @param sz 欲分配的内存大小
 * @param atype 欲分配的内存的种类
 * @return 已经分配的内存地址
 * @remark
 *
 * 在ARM中如果使用C++,必须重载new操作符
 */
void* operator new[]( size_t sz, int atype )
{
    if( sz == 0 )
        return NULL;
#ifdef USE_MEMMANGER
    void* test = (void*)( GETAPPINSTANCE() );
    
    CMemoryManger* manger = ( CMemoryManger* )( ( byte* )( GETAPPINSTANCE() ) + sizeof( AEEApplet ) );
    void* mi = manger->MemoryAlloc( atype, sz );
#else    
    void* mi = MALLOC( sz );
#endif
#ifdef _DEBUG1
        if( !mi )
        {
            DBGPRINTF("out memory");
        }
        else
        {
            MEMSTRUCT* toadd = (MEMSTRUCT*)MALLOC( sizeof( MEMSTRUCT ) );
            toadd->addr = mi;
            toadd->length = sz;
            iMemLog.Add(toadd);
        }
#endif
#ifdef TEST_MEM
        IHeap* pHeap= NULL;
        AEEApplet* pMe = (AEEApplet*)GETAPPINSTANCE();
        ISHELL_CreateInstance( pMe->m_pIShell, AEECLSID_HEAP, ( void** )( & pHeap ) );
        if( memuse == 0 )
        {
            used = memuse =  IHEAP_GetMemStats( pHeap );
        }
        if( IHEAP_GetMemStats( pHeap ) - memuse > used )
        {
            used = IHEAP_GetMemStats( pHeap ) - memuse;
        }
        IHEAP_Release( pHeap );
#endif
        return mi;
}
       

对new和new[]分别添加了参数,并且,并不推荐程序调用默认的new和new[],而是通过类似下面的方式进行调用:

       #define ELEAVE 0
       byte* ptr = new (ELEAVE) byte[10];
       

熟悉symbian的人应该对此很熟悉,delete和普通的没有区别。推荐的原因在于如果使用了内存管理器需要放在AEEApplet之后,类似下面这样:

       class test_MemoryAlloc
{
public:
    AEEApplet a; //!< First element of this structure must be AEEApplet
    CMemoryManger m_manger; //!< 内存管理器,必须放在AEEApplet的后面,由于AEEApplet是第一个元素,也就是说,内存管理器将是第二个元素。
    AEEDeviceInfo DeviceInfo; //!< always have access to the hardware device information
};
       

上述代码在查找内存检测的代码如下:

       #ifndef _H_MEMORYLOG
#define _H_MEMORYLOG
/*!
 * @struct MEMSTRUCT
 * @brief 内存检测用来记录内存的结构
 *
 * @copyright GPL
 */
typedef struct _MEMSTRUCT{
	void* addr;//!< 分配的内存地址
	int length;//!< 分配的内存征长度
	int count;//!< 分配时的分配索引值
	} MEMSTRUCT;
class CMemoryManger;
/*!
 * @class MEMORYLOG
 * @brief 内存记录
 *
 * @warning
 *
 * 内存检测仅仅可以在wins平台使用,ARM平台不可以使用
 * @copyright GPL
 */
class MEMORYLOG
	{
	private:
        friend class CMemoryManger;
		MEMSTRUCT** imem; //!< 已经记录的内存结构
		int num;//!< 目前已经记录的内存记录数目
		int maxnew;//!< 总共分配的内存次数
		int maxdelete;//!< 总共删除的内存次数
	public:
		/*!
		 * @fn MEMORYLOG
		 * @brief 构造函数
		 * 
		 */
		MEMORYLOG(): imem( NULL ), num( 0 ), maxnew( 0 ), maxdelete( 0 )
			{

			}
		/*!
		 * @fn Add( MEMSTRUCT* amem )
		 * @brief 添加一个记录结构
		 *
		 * @param amem 欲添加的记录结构指针
		 * @return 无
		 */
		void Add( MEMSTRUCT* amem )
			{
                MEMSTRUCT** temp = (MEMSTRUCT**)MALLOC( sizeof( MEMSTRUCT* ) * ( num + 1 ) );
                for( int i = 0;i < num; i++ )
                    temp[i] = imem[i];
                temp[num] = amem;
                FREE( imem );
                imem = temp;
                if( maxnew == 6 )
                    int k = 10;
                imem[num]->count = maxnew;
                num++;
                maxnew++;
			}
		/*!
		 * @fn SubNode( int aindex )
		 * @brief 从内存记录中删除一个记录
		 *
		 * @param aindex 欲删除的记录索引
		 * @return 无
		 */
		void SubNode( int aindex )
			{
                MEMSTRUCT** temp = (MEMSTRUCT**)MALLOC( sizeof( MEMSTRUCT* ) * ( num - 1 ) );
                for( int i = 0;i < num; i++ )
                    if( i != aindex )
                        temp[i] = imem[i];
                    else
                        break;
                FREE( imem[i] );
                for( i = i+1; i < num; i++ )
                    temp[i-1] = imem[i];
                FREE( imem );
                imem = temp;
                num--;
                maxdelete--;
			}
		/*!
		 * @fn Sub( void* aaddr )
		 * @brief 从内存记录中删除一个记录
		 *
		 * @param aaddr 分配了的内存地址
		 * @return 无
		 */
		void Sub( void* aaddr )
			{
                int i = 0;
                for( i = 0; i < num; i++ )
				{
                    if( imem[i]->addr == aaddr )
                        break;
				}
                if( i == num )
				{
                    return;
				}
                SubNode( i );
                
			}
		/*!
		 * @fn ~MEMORYLOG()
		 * @brief 析构函数
		 *
		 * @return 无
		 */
		~MEMORYLOG()
			{
                if( num != 0 )
				{
                    if( num > 0 )
					{
                        for( int i = 0;i < num; i++ )
                        {
					
                            char temp[255];
                            SNPRINTF(temp, sizeof(temp), "memory leak addr = %x, size = %d, count = %d", imem[i]->addr, imem[i]->length, imem[i]->count );
                            DBGPRINTF( temp );
                        }
					}
				}
                char temp[255];
                SNPRINTF(temp, sizeof(temp), "memory resulet new count = %d, delete count = %d", maxnew, maxdelete );
                DBGPRINTF( temp );
                for( int i = 0; i < num; i++ )
                    FREE(imem[i]);
                FREE( imem );
			}
};

#endif
       

上面的代码给我自己带来的最大的感受就是,我的耳根清静了不少,我告诉别人上面的如何使用,剩下的就是他们的事情了,这样比别人总来找我:“不好意思,这个程序不知道哪里出了内存泄漏,查找要很长时间”要好的多。

发布者

rix

如果连自己都不爱自己,哪还有谁来爱你