BREW HEAP管理

BREW通过IHEAP 接口可以管理BREW 堆栈。

IHeap接口及函数

OEM_GetinitHeapBytes() (OEMHeap.c中)可以设置用户使用堆栈的大小和位置

BREW开放IHeap接口函数,用于动态获取、释放内存和获取堆栈信息。BREW同时提供了一些助手函数,如MALLOC()等用于简化内存操作。OEM层也可以在静态应用开发中使用使用OEM_Malloc()、OEM_Free()等函数。

BREW 堆栈的管理

为了防止BREW应用引发内存泄露,BREW对BREW 应用分配的内存进行了跟踪。BREW为每个在BREW堆栈中分配的内存都维护了一个information block,称为堆栈节点。堆栈节点是一个32bit的ID,处于分配的内存地址的前4个字节中。比如,通过MALLOC()函数成功分配内存后返回的地址的前4个字节。

动态应用通过MALLOC()、REALLOC()或IHEAP_Malloc()、IHeap_Realloc()来分配内存。默认情况下,BREW会使用BREW app 模块上下文的32bit ID来标记分配的内存节点。即BREW用于跟踪应用内存的32bit ID事实上是每个module的ID,这意味着来自同一个module的两个应用可以拥有相同的32bit ID。

对于静态应用,可以使用MALLOC()、REALLOC()或者IHEAP_Malloc()、IHEAP_Realloc(),也可以使用OEM_Malloc()、OEM_Realloc()和sys_malloc()和sys_realloc()函数。在这些调用中,内存通常标记在system context 下。静态应用也可以在调用MALLOC()、REALLOC()或者IHEAP_Malloc()、IHEAP_Realloc()函数前将上下文改为system context,这会改变默认行为并导致分配的内存标记在system context下。

当一个应用退出时,BREW会在堆栈中查找标记为该应用的32bit ID的堆栈节点。一旦找到,BREW会调用OEMOS_BreakPoint()函数报告内存泄露然后自动释放相关分配的内存。BREW会在一个module中所有的应用都退出时才执行内存泄露检测。当在模拟器中发现内存泄露时,会直接报错,而在目标设备中,泄露会被清理回收。

BREW Extensions中BREW Heap的用法

当BREW应用创建一个extension实例时,将实例化该extension的IModule。在实例化extension的IModule时分配的内存与extension的module context相关联,分配的内存用extension的module context的32bit ID值进行标记。

当实例化IModule后,为该extension实例分配的任何其他内存都与BREW应用调用程序的module context相关,这些内存被标记为BREW 应用的32bit ID 值而不是extension的module context ID。

在system context中分配内存

当一个静态extension的接口只有一个实例并且被其他应用共享时,或者当它开放了一些底层资源时,比如解析一段buffer中的信息,该类实例的内存应当在system context中进行分配。如果extension是在system content 中分配的,那么在析构时应该注意确保资源的释放以免内存泄露。这可以通过增加引用并在AEE_Exit()时清除引用计数来强制释放。你可以通过注册一个系统回调,以便在AEE_Exit完成时强制释放内存并重置指针或全局变量。

如果一个extension对外提供了service,每个调用的应用都需要设置自己的数据,在这用情况下,最好的方式是在应用的module context下分配内存,并在每次调用MYExtension_New()时分配一次。如果可以的话,在应用中分配内存并只是将内存传入使用是最好的方式。如果在应用中需要获取内存的大小,可以提供一个计算方法的函数或在函数中添加一个输入输出参数。为了避免资源泄漏,最好通过使用AEE_LinkSysObject()函数将这些实例与正在执行的应用相关联来确保当该应用所属的module释放时执行析构函数。

检测内存泄露

BREW应用引发的内存泄露可以在应用所属的module释放时被检测出来。

可以通过在OEMOS_Breakpoint()中设置断点来检测。

AEEAppLeak结构中包含了内存泄露的详细信息。

+ expand sourceview plaincopy to clipboardprint?
AEEAppLeak  
//********************************************************************************************************************************  
//  
// Used for AEEOS_Breakpoint  
//  
//******************************************************************************************************************************** 
#define AEEBRK_MEMLEAK     0x00000001 
#define AEEBRK_IFACELEAK   0x00000002 
#define AEEBRK_CORRUPTNODE 0x00000003 
#define AEEBRK_EXCEPTION   0x00000004  
 
//  
// AEEAppLeak - passed to AEEOS_Breakpoint() for AEEBRK_MEMLEAK and AEEBRK_IFACELEAK  
//  
typedef struct _AEEAppLeak  
{  
   void *   pBuffer;          // Buffer Leaked  
   uint32   dwMemGroup;       // Group ID of the owner of the buffer  
} AEEAppLeak; 
AEEAppLeak
//********************************************************************************************************************************
//
// Used for AEEOS_Breakpoint
//
//********************************************************************************************************************************
#define AEEBRK_MEMLEAK     0x00000001
#define AEEBRK_IFACELEAK   0x00000002
#define AEEBRK_CORRUPTNODE 0x00000003
#define AEEBRK_EXCEPTION   0x00000004

//
// AEEAppLeak - passed to AEEOS_Breakpoint() for AEEBRK_MEMLEAK and AEEBRK_IFACELEAK
//
typedef struct _AEEAppLeak
{
   void *   pBuffer;          // Buffer Leaked
   uint32   dwMemGroup;       // Group ID of the owner of the buffer
} AEEAppLeak;

AEE_GetMemGroupName(pal-dwMemGroup, szBuff, sizeof(szBuff));可以获知所属的应用。

AEEAppLeak中的pBuffer指向了泄露的内存,因此,你可以通过dump该buffer来辨识。buffer可以方便的通过在data.dump中

查找到。+ expand sourceview plaincopy to clipboardprint?
void OEMOS_Breakpoint(uint32 dwType, void * pData, uint32 nSize)  
{  
   // You can ASSERT here for debug builds if you wish...  
   // For now this will only print a debug message to show proper usage  
   // of the incoming parameters.  
   switch(dwType){  
   case AEEBRK_MEMLEAK:  
   case AEEBRK_IFACELEAK:  
      {  
         AEEAppLeak * pal = (AEEAppLeak *)pData;  
 
         if( pal && nSize == sizeof(AEEAppLeak) ){  
            char szBuff[64];  
 
            *szBuff = 0;  
            AEE_GetMemGroupName(pal->dwMemGroup, szBuff, sizeof(szBuff));  
 
        // Add an entry to a backtrace file fs:/shared/memleak.<appname>.bt,  
        // where <appname> is the string szBuff. 
 
#ifdef FEATURE_BREW_HEAP_TRACKER  
            {  
              static char filename[256];  
              SPRINTF(filename, "/err/memleak.%s.bt", szBuff);  
 
          // AEEHeapNode structure is 8 bytes in BREW 3.1.5, but it  
          // is 4 bytes in BREW 3.1.4 
#if MIN_BREW_VERSIONEx(3,1,5)  
              print_allocation(filename, ((char *)pal->pBuffer) - (sizeof(uint32)*2)); 
#else  
              print_allocation(filename, ((char *)pal->pBuffer) - sizeof(uint32)); 
#endif  
            } 
#endif//FEATURE_BREW_HEAP_TRACKER  
            DBGPRINTF("BPOINT Type %d, %s 0x%p %s", dwType,   
                        (dwType == AEEBRK_MEMLEAK ? "Node" : "IFace"),   
                        pal->pBuffer, szBuff);  
         }  
      }  
      break;  
   case AEEBRK_EXCEPTION:  
      {  
         AEEExceptionType * pet = (AEEExceptionType *)pData;  
 
         if( pet && nSize ){  
            DBGPRINTF("BPOINT Type %d, Exception: %d", dwType, *pet);  
         }  
      }  
      break;  
   case AEEBRK_CORRUPTNODE:  
      { 
#if !defined(PLATFORM_LTK) && defined(FEATURE_BREW_HEAP_DOUBLE_FREE_DETECT)  
         AEEAppLeak * pal = (AEEAppLeak *)pData;  
         if( pal && nSize == sizeof(AEEAppLeak) )  
         {  
 
          // The BREW allocation offset is number of bytes of overhead in each  
          // BREW allocation.  Currently BREW reserves 4 bytes for the module  
          // ID in each allocation that it requests from the OEM heap.  We need  
          // to backtrace by that many bytes before we feed the pointer to the  
          // OEM heap again.  
          //  
          // NOTE:  This value must be changed accordingly if the size of the  
          //        BREW heap overhead changes!  Unfortunately, BREW does not  
          //        expose that information in a header, so we have to do that  
          //        manually. 
 
#define BREW_ALLOC_OVERHEAD (sizeof(uint32))  
 
            extern void report_double_free_if_necessary(char *modname, void *ptr); 
 
#ifdef FEATURE_BREW_HEAP_INIT_MEM_ON_FREE  
 
          // When initialize-on-free is enabled, we will overwrite the module  
          // id when freeing an allocation. In this case, calling  
          // AEE_GetMemGroupName() is pointless.  In this case, we pass NULL  
          // for the module-name pointer, which will instruct function  
          // report_double_free_if_necessary() to create a file with the  
          // allocation address in its name (e.g., /err/doublefree.0x12345678.bt)  
          // instead of with the module name (e.g., // /err/doublefree.MessagingApp.bt)  
 
            extern boolean zf_enabled;  
            if (zf_enabled)  
            {  
               report_double_free_if_necessary(NULL,  
                                            ((char *)pal->pBuffer) - BREW_ALLOC_OVERHEAD);  
            }  
            else
#endif  
            {  
               static char szBuff[64];  
               *szBuff = 0;  
               AEE_GetMemGroupName(pal->dwMemGroup, szBuff, sizeof(szBuff));  
               report_double_free_if_necessary(szBuff,  
                                            ((char *)pal->pBuffer) - BREW_ALLOC_OVERHEAD);  
            }  
         } 
#endif//not PLATFORM_LTK && FEATURE_BREW_HEAP_DOUBLE_FREE_DETECT  
         DBGPRINTF("BPOINT Type %d, Address: 0x%p", dwType, pData);  
         // Determine if you want to walk the heap with AEEkHeap_Walk()  
      }  
      break;  
   default:  
      {  
         DBGPRINTF("BPOINT Unknown!");  
      }  
      break;  
   }  

void OEMOS_Breakpoint(uint32 dwType, void * pData, uint32 nSize)
{
   // You can ASSERT here for debug builds if you wish...
   // For now this will only print a debug message to show proper usage
   // of the incoming parameters.
   switch(dwType){
   case AEEBRK_MEMLEAK:
   case AEEBRK_IFACELEAK:
      {
         AEEAppLeak * pal = (AEEAppLeak *)pData;

         if( pal && nSize == sizeof(AEEAppLeak) ){
            char szBuff[64];

            *szBuff = 0;
            AEE_GetMemGroupName(pal->dwMemGroup, szBuff, sizeof(szBuff));

        // Add an entry to a backtrace file fs:/shared/memleak.<appname>.bt,
        // where <appname> is the string szBuff.

#ifdef FEATURE_BREW_HEAP_TRACKER
            {
              static char filename[256];
              SPRINTF(filename, "/err/memleak.%s.bt", szBuff);

       // AEEHeapNode structure is 8 bytes in BREW 3.1.5, but it
       // is 4 bytes in BREW 3.1.4
#if MIN_BREW_VERSIONEx(3,1,5)
              print_allocation(filename, ((char *)pal->pBuffer) - (sizeof(uint32)*2));
#else
              print_allocation(filename, ((char *)pal->pBuffer) - sizeof(uint32));
#endif
            }
#endif//FEATURE_BREW_HEAP_TRACKER
            DBGPRINTF("BPOINT Type %d, %s 0x%p %s", dwType,
                        (dwType == AEEBRK_MEMLEAK ? "Node" : "IFace"),
                        pal->pBuffer, szBuff);
         }
      }
      break;
   case AEEBRK_EXCEPTION:
      {
         AEEExceptionType * pet = (AEEExceptionType *)pData;

         if( pet && nSize ){
            DBGPRINTF("BPOINT Type %d, Exception: %d", dwType, *pet);
         }
      }
      break;
   case AEEBRK_CORRUPTNODE:
      {
#if !defined(PLATFORM_LTK) && defined(FEATURE_BREW_HEAP_DOUBLE_FREE_DETECT)
         AEEAppLeak * pal = (AEEAppLeak *)pData;
         if( pal && nSize == sizeof(AEEAppLeak) )
         {

          // The BREW allocation offset is number of bytes of overhead in each
          // BREW allocation.  Currently BREW reserves 4 bytes for the module
          // ID in each allocation that it requests from the OEM heap.  We need
          // to backtrace by that many bytes before we feed the pointer to the
          // OEM heap again.
          //
          // NOTE:  This value must be changed accordingly if the size of the
          //        BREW heap overhead changes!  Unfortunately, BREW does not
          //        expose that information in a header, so we have to do that
          //        manually.

#define BREW_ALLOC_OVERHEAD (sizeof(uint32))

            extern void report_double_free_if_necessary(char *modname, void *ptr);

#ifdef FEATURE_BREW_HEAP_INIT_MEM_ON_FREE

          // When initialize-on-free is enabled, we will overwrite the module
          // id when freeing an allocation. In this case, calling
          // AEE_GetMemGroupName() is pointless.  In this case, we pass NULL
          // for the module-name pointer, which will instruct function
          // report_double_free_if_necessary() to create a file with the
          // allocation address in its name (e.g., /err/doublefree.0x12345678.bt)
          // instead of with the module name (e.g., // /err/doublefree.MessagingApp.bt)

            extern boolean zf_enabled;
            if (zf_enabled)
            {
               report_double_free_if_necessary(NULL,
                                            ((char *)pal->pBuffer) - BREW_ALLOC_OVERHEAD);
            }
            else
#endif
            {
               static char szBuff[64];
               *szBuff = 0;
               AEE_GetMemGroupName(pal->dwMemGroup, szBuff, sizeof(szBuff));
               report_double_free_if_necessary(szBuff,
                                            ((char *)pal->pBuffer) - BREW_ALLOC_OVERHEAD);
            }
         }
#endif//not PLATFORM_LTK && FEATURE_BREW_HEAP_DOUBLE_FREE_DETECT
         DBGPRINTF("BPOINT Type %d, Address: 0x%p", dwType, pData);
         // Determine if you want to walk the heap with AEEkHeap_Walk()
      }
      break;
   default:
      {
         DBGPRINTF("BPOINT Unknown!");
      }
      break;
   }
}

低内存提示

在BREW 3.1中,BREW应用可以注册低内存通知并定制释放内存方法。当BREW 应用在调用MALLOC失败并且没有足够内存时,就会触发低内存通知。

应用可以通过调用ISHELL_OnLowRam()或者ISHELL_RegisterSystemCallback()并把nSCBType设为AEE_SCB_LOW_RAM来注册一个当系统达到低内存条件时触发的回调函数。这允许应用进行相应的内存处理。

应用也可以通过调用ISHELL_OnLowRamCritical()或者ISHELL_RegisterSystemCallback()并把nSCBType设为AEE_SCB_LOW_RAM_CRITICAL来注册一个回调函数,以便在系统达到低内存条件并且使用AEE_SCB_LOW_RAM回调无法获取足够的RAM时能够释放更多的内存。调用应用必须属于AEEGROUPID_LOW_RAM以便成功注册该回调。

一旦BREW应用注册接收低内存通知,BREW会首先将低内存通知发给注册该通知的应用,该应用接收到通知后会释放更多可用内存,在这个通知之后,BREW会再次检测可用内存,如果所需的内存仍然不够,BREW 会发出critical low RAM notification给那些注册了改通知的应用。

如果没有应用注册了低内存或紧急低内存通知,或者发出通知后释放的内存仍然不够,BREW会尝试通过卸载application stack中的应用来释放自己的内存。

BREW通过自己的方式释放位于current top visible应用下的第一个挂起的应用。它从内存中卸载该应用(该应用会接收到EVT_APP_STOP事件),但是,该应用在应用历史堆栈中的实体却没有删除,这就允许BREW在当前激活应用退出时自动重启该应用。

卸载了一个应用之后,BREW会检测可用内存是否满足MALLOC请求,如果满足,则MALLOC返回成功,如果仍然没有足够的内存,BREW会继续卸载堆栈中的下一个应用,直到它获取足够的可用内存来满足MALLOC请求。如果卸载了所有应用(不包括当前激活应用),而内存仍然不足,BREW会在MALLOC中返回NULL。

在BREW释放内存的整个过程中,并不会牵涉到后台应用。当top visible应用退出时,BREW重新加载挂起的应用并且向该应用发出resume事件。resume的应用可以获取其在应用中保持的任何数据,因为BREW在a卸载该应用的时候依旧保留了改应用的AppHistory entry。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/feimor/archive/2009/12/16/5020521.aspx

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值