




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
MOCOR平台内存管理介绍及案例分析MOCOR平台内存管理介绍MOCOR内存管理的基本架构
ThreadX的内存管理MOCOR的内存管理MOCOR内存bug实例分析3/10/20232MOCOR内存管理的基本架构一般的嵌入式系统中最基本的内存管理方案有两种——静态分配和动态分配。静态分配是指在编译或链接时将程序所需的内存空间分配好。采用这种分配方案的内存段,其大小一般在编译时就能够确定。静态分配比较简单,一般不需要特殊的管理。动态分配是指系统运行时根据需要动态地分配内存,为实现动态分配,系统里需要有一套完善的管理机制。本文中所指的内存管理,就是指动态分配内存的管理。3/10/20233MOCOR内存管理的基本架构从可用的内存资源的角度,还可以得到下面的一个内存分配图。3/10/20235MOCOR平台内存管理介绍MOCOR内存管理的基本架构ThreadX的内存管理
MOCOR的内存管理MOCOR内存bug实例分析3/10/20236ThreadX的内存管理
内存字节池(BTYEPOOL)内存块池(BLOCKPOOL)3/10/20237ThreadX的内存管理---内存字节池1.基本概念:内存字节池是一个连续的内存块。在字节池中,内存的分配以字节为单位,任意大小的内存都可以在字节池上分配(受限于内存的容量)。内存字节池类似于C语言里的堆(heap),所以,字节池我们也可以把它叫做字节堆,代码里我们也可以看到创建的字节池通常以heap来命名。但与一般意义上的堆的不同在于,ThreadX里的字节池可以有多个,MOCOR平台也是利用了这一特性,根据不同的需求而创建了多个heap。每一个字节池都有一个相应的字节池控制块,通常是一个全局结构。控制块包括对内存池的定义和状态,比如内存池的名字,可用的字节数等。该结构的定义如下:3/10/20239ThreadX的内存管理---内存字节池3/10/202310ThreadX的内存管理---内存字节池2.分配方式:从字节池中分配内存类似于C语言的malloc调用,该调用返回所需内存的数量(以字节为单位)。分配的原则是“首次符合”原则,就是说,当第一个空闲内存块的大小满足需求时,就从该内存块分配内存,然后将该内存块的剩余内存转换成一个新块。字节池在初始状态下,只有一个空闲块,以后随着随着分配的进行,内存块会随之增多。除了上述的分配原则之外,字节池里还定义了一个值BYTE_POOL_SLIP_SIZE。这是在代码里实现指定的一个具体数值,在分配内存时,如果要分配的内存大小大于这一数值,则从字节池的底部开始分配。采用这种分配方式是为了减少内存碎片的产生,尽量把大内存的分配区域和小内存的分配区域分开。目前系统里定义的BYTE_POOL_SLIP_SIZE为80K。3/10/202311ThreadX的内存管理---内存字节池注意:首先要注意的问题是碎片,一个字节池可能有2000字节的可用空间,但不保证一定能分配到2000字节的连续空间,内存池对连续字节的数量不做保证。分配一块内存所需要的时间跟分配内存的大小,字节池中的碎片数等因素有关,如果字节池有2000字节的空闲块,花多长时间找到这块内存也是没有保证的。因此,在时间要求苛刻的任务中应避免使用字节池。字节池不能在中断函数里使用,也不能在timer回调函数里使用。3/10/202313ThreadX的内存管理---内存字节池思考:假定系统中有一个内存字节池,并且已经从中分配了几次内存。当内存池中还有500字节的剩余内存时,应用程序申请200字节的内存,在什么情况下,这样的申请不能满足?3/10/202314ThreadX的内存管理内存块池(BLOCKPOOL)3/10/202315ThreadX的内存管理---内存块池3/10/202317ThreadX的内存管理---内存块池2.分配方式:内存块池中分配内存是非常快的,主要得益于内存块池中的所有空闲内存块组成一个链表(即上面结构中的tx_block_pool_available_list)。每次分配时只需要取链表头即可,无须遍历内存块池来找到空闲块。3/10/202318ThreadX的内存管理---内存块池3.内存布局:3/10/202319MOCOR平台内存管理介绍MOCOR内存管理的基本架构ThreadX的内存管理MOCOR的内存管理MOCOR内存bug实例分析3/10/202321MOCOR内存管理
MOCOR平台在ThreadX内存管理的基础上,又做了进一步的封装,这样可以更便于上层应用调用。前面我们已经了解了ThreadX是如何对内存进行管理的,下面我们从底层来到上层,看一看MOCOR是如何利用Threadx的内存管理机制来建立自己的内存管理方式。之前的MOCOR文档里,将内存字节池称为堆(heap),而将内存块池称为内存池(pool),我们也延续这种说法,请注意不要混淆。3/10/202322MOCOR内存管理1.堆内存(heap)管理:MOCOR平台的堆内存就是前面讲到的内存字节池。最早的MOCOR平台只有一个内存堆,但在实际使用中发现,程序运行时往往要交错的分配一些动态内存和常驻内存,这样会产生很多无法消除的内存碎片。同时base等通讯模块同上层应用又是并发的,这样无规律的分配也会造成很多内存碎片。为了解决这种情况,后来MOCOR版本将内存堆分成了三块,也就是创建了三个内存字节池作为heap。这三个字节池的分别是:dynamicbaseheap,staticheap和dynamicappheap。同样,对应着三个heap也有三个不同的接口,分别是:SCI_ALLOC_BASE,SCI_ALLOC_CONSTSCI_ALLOC_APP。3/10/202323MOCOR内存管理三个heap的大小都定义在mem_cfg.c里:#defineMAX_STATIC_HEAP_SIZE (600*1024)#defineMAX_DYNAMIC_BASE_HEAP_SIZE(60*1024)#defineMAX_DYNAMIC_APP_HEAP_SIZE (1430*1024)#define BYTE_HEAP_SIZE(MAX_STATIC_HEAP_SIZE+MAX_DYNAMIC_BASE_HEAP_SIZE+MAX_DYNAMIC_APP_HEAP_SIZE)3/10/202325MOCOR内存管理系统assert之后,选择菜单5,可以看到所有heap上的内存分配信息,类似这样:3/10/202326MOCOR内存管理什么时候在heap上分配,什么时候在内存池上分配?MOCOR对分配内存的位置有如下的约定:只有分配的内存的大小超过mem_cfg.c里定义的最大的内存块池的大小,内存才会在heap里分配,否则就在内存块池里分配。目前MOCOR平台定义的最大的内存块池是1600字节,也就是大于1600字节的内存才在heap里分配。3/10/202329MOCOR内存管理MOCOR在内存池上的分配策略是:最小适配原则:按从小到大的顺序,遍历所有的内存池,直到找到一个内存池,其大小大于欲分配内存的大小,就在该内存池分配内存。如果该内存池已被用尽,则继续向下遍历,找到下一个适合的内存池。如果全部遍历完都没有找到可用的内存池,则改为在heap上分配内存。上面的策略对于上层的申请者是透明的,申请者只要传入欲分配的内存大小即可,无须关心内存究竟是在哪里分配的。3/10/202330MOCOR内存管理系统assert之后,选择菜单5,可以看到当前所有pool的信息,类似这样:3/10/202331MOCOR内存管理3.内存Debug信息:为了方便在出现内存问题的时候调试,通常在分配内存的时候(heap和pool),会额外的多分配一个header,放在每一块分配内存的开始。header的结构定义如下:结构成员的意义如下:pre,succ:两个指向header结构的指针,目的是将所有的header串成一张双向链表。,line:分配该块内存的文件名和行号size:内存大小(不包括header)block_num:系统分配的内存块总计此外,为了能检查内存越界,在每一块分配内存的最后也会额外多分配一个字节做为ENDFLAG,内存分配时该字节会被写入0xAA。当该内存被释放时,会检查该标志位,如果不为0xAA,则说明出现异常,系统ASSERT。3/10/202332MOCOR内存管理加入debug信息后的内存如下:3/10/202333MOCOR内存管理因为有额外加了这些debug信息,所以如果我们要分配N个字节的内存,那么实际上分配的大小是:N+sizeof(MEM_HEADER_T)+1.再考虑到字节对齐的需要,实际的空间比上面的数字可能还要大一点。比如16字节的内存池,其中每个内存块的大小其实是:16+24+4(本应是加1,加4是为了字节对齐)Header里的pre指向前一块分配的内存,next指向后一块分配的内存,所有分配的内存,都通过header里的pre和succ指针串起来,构成一张双向链表。每分配一块新的内存,就将这块内存的header加到链表的最后。通过遍历header构成的链表,我们可以得到当前所有分配的内存块的信息。3/10/202334MOCOR内存管理系统assert之后,选择菜单4,就可以打印出这些信息,类似这样:3/10/202335MOCOR内存管理思考:应用里分配一块大小为N字节的内存,实际在内存里占了多少空间?3/10/202336MOCOR内存管理练习:前面我们已经讲了MOCOR平台各类内存的分配情况,下面需要你亲自动手加深理解。使用我们的样机,连上log,主动assert,输入3,dump出当前的内存。输入5,打出当前的内存信息。然后打开内存dump文件,找到appheap的起始地址,从起始地址开始,推出整个appheap的所有内存块的信息,然后用刚才打印出的信息验证一下你的推导是否正确。3/10/202337MOCOR内存管理4.物理内存:内存管理的最终的对象就是物理内存,但是,物理内存并不能全部用于动态分配,因为一些全局变量,代码等需要占用物理内存,这些相当于静态分配。而我们通常说的内存管理是指动态的对内存进行分配和释放。那么哪些物理内存是我们能够动态分配使用的呢,我们是如何知道可以动态分配的物理内存的地址范围呢?以6600L芯片为例,L所用的NORMCP中的SRAM通常是4M,这4M就是我们所能够用到的所有物理内存。OS启动后,会把物理内存SRAM的地址映射到0x04000000到0x04400000这个区域。3/10/202338MOCOR内存管理Heap和pool对应的物理内存的位置和大小:uint32pool_1_addr[POOL_XX_SIZE(POOL_1_BLOCK_SIZE,POOL_1_BLOCK_NUM)];uint32pool_2_addr[POOL_XX_SIZE(POOL_2_BLOCK_SIZE,POOL_2_BLOCK_NUM)];uint32pool_3_addr[POOL_XX_SIZE(POOL_3_BLOCK_SIZE,POOL_3_BLOCK_NUM)];………uint32pool_B_addr[POOL_XX_SIZE(POOL_B_BLOCK_SIZE,POOL_B_BLOCK_NUM)];uint32pool_C_addr[POOL_XX_SIZE(POOL_C_BLOCK_SIZE,POOL_C_BLOCK_NUM)];uint32BYTE_HEAP_ADDR[byte_head_size>>2];3/10/202339MOCOR内存管理5.内存委托管理:委托内存管理实质就是给了模块创建自己的heap和pool的机会。通常情况下我们使用的heap和pool都是系统创建的。但有些模块也想先从系统的heap里分出一块大内存,然后在这块大内存上,再根据自己的需要细分出一些内存块来供本模块使用。在没有委托内存管理之前,这种细分的工作实际由各模块自己来完成,实现的手法也五花八门。有了委托内存管理,模块可以在分配的大内存的基础上,再创建自己的heap和pool,这些heap和pool的实现机制,同我们之前讲的系统的机制是基本一样的。3/10/202340MOCOR内存管理6.BLOCKMEM:关于BLOCKMEM可以参考《MOOCR应用模块内存使用接口》的第二章,如果还不清楚blockmem的目的和用法的,请务必先学习上面这篇文档。3/10/202341MOCOR内存管理几个容易混淆的地方:1.BLOCKMEM并不是在内存中实际分配出一块区域来进行管理(虽然旧的MOCOR版本上确实是这样的),BLOCKMEM的分配依然是在appheap上完成的。既然是在appheap上分配的,那么assert之后按5,从appheap的信息里是可以找到当前分配的blockmem的,比如这样:3/10/202342MOCOR内存管理3/10/202343MOCOR内存管理2.BLOCKMEM的管理机制中,为各块mem都定义了一个offset,但这个offset纯粹是一个逻辑概念,它的作用是在分配blockmem时判断是否存在mem冲突。一个block在内存中的实际位置同这个offset没有任何关系。3/10/202344MOCOR内存管理MOCOR内存管理的基本架构ThreadX的内存管理MOCOR的内存管理MOCOR内存bug实例分析3/10/202345MOCOR内存bug实例分析内存不足:内存不足是经常遇到的问题,内存不足根据产生的原因,还可以分为内存泄露引起的不足,内存碎片引起的不足,以及真正的内存不足。下面我们以几个具体的例子来分析。3/10/202346MOCOR内存bug实例分析1.内存泄漏:内存泄露是指分配了一块内存在使用完后却没有释放,造成系统中可用内存越来越少,最后死机。内存泄露引起的死机很容易定位,只要在死机后输入4,打出当前所有分配的内存信息,查看是否有大量的重复的内存分配就可以知道。实例:某客户项目,测试中反复拨号出现死机,死机信息为:File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),mmipb_wintab.c,line=11550,param=0x4650)打出当前所有分配的信息,发现异常,有一条分配信息出现多次:3/10/202347MOCOR内存bug实例分析3/10/202348MOCOR内存bug实例分析2.内存碎片:如果系统中存在内存碎片,可能会出现虽然剩余的总内存数是足够的,但依然分配不出内存的情况。实例,某客户项目,后台运行QQ,进入DC后死机。File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),block_mem.c,line=563,param=0x113004)从死机信息可以看出,要分配的内存大小为0x113004(),这么大的内存只可能从heap上分配,查看appheap的信息如下:3/10/202349MOCOR内存bug实例分析3/10/202350MOCOR内存bug实例分析我们重点关注画红圈的三块内存,可以看到,剩余的总内存1495344,大于欲分配的内存,但是编号1和3的两块空闲内存正好被编号2的内存隔开了,1,和3的大小都不超过1126404,所以无法分配,这就是一个典型的内存碎片造成内存不足的场景。要解决这个问题,我们就要想办法把两块空闲内存连在一起,主要就是要调整这几块内存的分配和释放的顺序。我们不妨用逆向思维来分析,先看一下造成内存碎片的顺序是怎样的,然后我们只要避免这种顺序就可以了。首先在最初时,1,2,3这三块内存实际是一整块空闲内存。前面我们提过,字节池分配内存时有一个反向分配的概念,当要分配的的内存大于80K时,是从底向上分配的。所以分配和释放的顺序是:第一步:分配内存3;第二步:分配内存2;第三步:释放内存3由此可以自然的想到解决的办法,就是调整上面的3个步骤,具体可以有两种办法:内存块2先于3分配,这样3释放后自然同1连在一起。内存块2在3释放之后再分配,这样2占了内存3的位置,剩余的内存也是连续的。具体用什么方法,就要根据实际的具体情况,看哪一种方法是最可行的。在客户的这个问题中,内存块3是一个第三方桌面插件分配的,内存块2是QQ分配的。所以第2种方法最可行,在分配QQ的内存前,先释放掉第三方桌面插件的内存,问题由此解决。3/10/202351MOCOR内存bug实例分析注意:并不是所有的内存碎片问题都能够通过这样的调整来得到解决。系统运行的过程中,一些内存碎片的产生是无法避免的,这种情况下内存碎片无法得到消除或消除的难度很大。3/10/202352MOCOR内存bug实例分析3.实际内存不足:如果出现剩余的内存不够分配,此时查看内存分配的情况也没有异常(也就是说已经排除了内存泄露和碎片的原因),这种情况就是真正的内存不足了。遇到这种情况,一般有这些思路:要求客户裁剪功能,减少内存的使用,通常客户会对平台版本进行一些定制,比如增加一些第三方应用等等,这些新增的模块往往会造成内存使用的增加。如果某些操作很耗内存,那么执行这些操作时最好将其他操作退出,尽量避免并发。以上都不行的话最后只能通过增大heapsize来解决。3/10/202353MOCOR内存bug实例分析某客户上报问题,进文件管理器,选择一张gif图片发彩信时出现内存不足死机:File:RTOS\source\src\c\threadx_mem.cLine:494ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),block_mem.c,line=521,param=0x25804)从上面的信息可以看到欲分配的内存大小是0x25804(153604)。查看appheap的使用情况如下3/10/202354MOCOR内存bug实例分析3/10/202355MOCOR内存bug实例分析可以看到当前剩余的总内存也不过是141744,其中最大一块空闲内存是0x1aa4c(109132),还差0x25804-0x1aa4c=0xADB8(44472)才够分配。我们用刚才的几种思路分析一下:裁剪功能,因为没有第三方的东西,这个不考虑避免并发。通过分析内存,可以看到分配的内存实际上可以分为两大块(见上图),一块是上面红框的部分,主要是由FMM分配的。另一块是下面红框部分,主要是由MMS分配,所以这里存在MMS和FMM并发的情况。如果我们在发送彩信之前就先退出FMM的话,可以解决此问题。增大heap。前面我们已经算出当前差了44472字节,修改mem_cfg.c,将appheap的大小增加至少44K。需要注意的是,如果要增大heap,首先要确认一下当然ram是否还有这么多可用的空间,可以通过查看map文件最后的几行信息:TotalROSize(Code+ROData)7530419(7353.92kB)TotalRWSize(RWData+ZIData)3944375(3851.93kB)TotalROMSize(Code+ROData+RWData)7586078(7408.28kB)红色的RWsize就是我们要关注的,可以看到当前RW使用了3851K,而RAM的总数是4096K,所以还有充足的空间,heap增加个几十K没有什么问题。可以看到使用2和3都可以解决问题,通常把增大heap作为最后的手段。3/10/202356MOCOR内存bug实例分析内存覆盖:内存覆盖也是常见的一类内存问题,引起内存覆盖的原因很多,往往没有固定规律可循。而且有时出现覆盖后并不立刻死机,这样无法确认第一现场,增大了解决问题的难度。但在MOCOR平台下,我们有一个非常有用的工具:BusMonitor。利用BusMonitor(后文简称BM),我们有一个解决覆盖问题的一般性思路:首先确定被覆盖内存的地址(可能是一个地址范围),如果问题可以重现,且每次被覆盖的地址比较固定,则可以用BM监控被覆盖的地址,这样当内存被覆盖时会第一时间死机,可以迅速定位。BusMonitor的用法比较简单,可以参考相关文档。3/10/202357MOCOR内存bug实例分析1.案例一内存写入时越界是出现内存覆盖的一个常见原因,相对来说也比较好查的,只要找到越界的那块内存基本就可以定位,我们看下面的例子:客户项目发现进入电话本偶而会出现死机,死机现场:File:RTOS\source\src\c\threadx_mem.cLine:364ASSERT(ASSERT:Error0x10(Nomemory,unabletoallocate!),wdp_customer.c,line=2098,param=0xFA4)初一看好像是个内存不足的,但实际不是,assert界面输入4后打出当前分配的内存,就会发现有错误:3/10/202358MOCOR内存bug实例分析3/10/202359MOCOR内存bug实例分析可以看到最后一行“memoryiscorrupted”,表明在遍历memheader的链表时出错,这意味着某一块memory的header异常了,而且这块内存的地址是0x40bcc30。Assert界面输入3,dump出当前内存后,我们打开dump文件,找到0x00bcc30这个地址:
3/10/202360MOCOR内存bug实例分析3/10/202361MOCOR内存bug实例分析0x000bcc30之前的24个字节,就是该块内存的header,我们看到,next指针明显异常,说明至少next指针被覆盖了。然后再往前看,上一块内存的结束标志(ENDFLAG)也异常了,说明了上块内存的结束标志也被覆盖了。此外,我们再往前看
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 仓储设备购销合同
- 建筑合同范本例子
- 互联网广告合作合同范本
- 退保咨询合同范本
- 钓场加盟合同范本
- 《我的叔叔于勒》教学设计
- 商品交货合同
- 第四单元写作《学习缩写》教学设计 2024-2025学年统编版语文九年级上册
- 高中信息技术必修教学设计-1.1 信息及其特征3-粤教版
- 第二单元 大单元教学设计2024-2025学年七年级语文上册同步备课系列(统编版2024)
- 人教版高一下英语单词表
- 2025年中国远洋海运集团限公司中石化中海船舶燃料供应限公司招聘26人高频重点模拟试卷提升(共500题附带答案详解)
- 专项训练:电磁感应中的电路、电荷量及图像问题(10大题型)(原卷版)
- 2025年春季学期各周国旗下讲话安排表+2024-2025学年度第二学期主题班会安排表
- 《幼儿教育政策与法规》教案-单元1 幼儿教育政策与法规
- 【语文】第23课《“蛟龙”探海》课件 2024-2025学年统编版语文七年级下册
- 2024年决战行测5000题言语理解与表达(培优b卷)
- 《现代企业管理学》本科教材
- 《中国人民站起来了》课件+2024-2025学年统编版高中语文选择性必修上册
- 初中语文现代文阅读训练及答案二十篇
- 单值-移动极差控制图(自动版)
评论
0/150
提交评论