BREW Heap 管理 -读书笔记

本文介绍了BREW环境中堆栈的管理方法,包括内存分配、释放、跟踪及低内存提示等内容。深入探讨了BREW如何通过IHeap接口管理堆栈,以及如何预防和检测内存泄露。
AI助手已提取文章相关产品:

原文出处:http://www.docin.com/p-36672037.html 

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结构中包含了内存泄露的详细信息。

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中

查找到。
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。

您可能感兴趣的与本文相关内容

内容概要:本文围绕六自由度机械臂的人工神经网络(ANN)设计展开,重点研究了正向与逆向运动学求解、正向动力学控制以及基于拉格朗日-欧拉法推导逆向动力学方程,并通过Matlab代码实现相关算法。文章结合理论推导与仿真实践,利用人工神经网络对复杂的非线性关系进行建模与逼近,提升机械臂运动控制的精度与效率。同时涵盖了路径规划中的RRT算法与B样条优化方法,形成从运动学到动力学再到轨迹优化的完整技术链条。; 适合人群:具备一定机器人学、自动控制理论基础,熟悉Matlab编程,从事智能控制、机器人控制、运动学六自由度机械臂ANN人工神经网络设计:正向逆向运动学求解、正向动力学控制、拉格朗日-欧拉法推导逆向动力学方程(Matlab代码实现)建模等相关方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握机械臂正/逆运动学的数学建模与ANN求解方法;②理解拉格朗日-欧拉法在动力学建模中的应用;③实现基于神经网络的动力学补偿与高精度轨迹跟踪控制;④结合RRT与B样条完成平滑路径规划与优化。; 阅读建议:建议读者结合Matlab代码动手实践,先从运动学建模入手,逐步深入动力学分析与神经网络训练,注重理论推导与仿真实验的结合,以充分理解机械臂控制系统的设计流程与优化策略。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值