移动_黄烨明_基于VxWorks的内存管理和一个内存泄漏查找实例_第1页
移动_黄烨明_基于VxWorks的内存管理和一个内存泄漏查找实例_第2页
移动_黄烨明_基于VxWorks的内存管理和一个内存泄漏查找实例_第3页
移动_黄烨明_基于VxWorks的内存管理和一个内存泄漏查找实例_第4页
移动_黄烨明_基于VxWorks的内存管理和一个内存泄漏查找实例_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、基于VxWorks的内存管理和一个内存泄漏查找实例本文主要分三部分,第一章介绍基于VxWorks的内存管理的主要内容,第二章介绍应用在ZXWR NB01产品软件设计中OSS的内存管理方法,第三章介绍实际应用中一个内存泄漏查找的实例。Chapter 1 基于VxWorks的内存管理一、 综述对于一个采用了VxWorks操作系统的主处理器构成的系统,主内存的管理机制主要由BSP来实现,包括内存的初始化和内存的访问接口;主内存的初始化由romInit()实现,总线访问(对设备而言)在sysHwInit()中初始化;BSP对内存访问的支持和管理策略:l 主内存的配置l 对MMU的虚拟映射l Cache

2、策略l 内存探针BSP的硬件寄存器在sysHwInit中初始化,通常的设备(串口除外)寄存器当设备初始化时被初始化;为调示方便,在BSP开发期间禁止cache和MMU直到以下的情况实现:l 内核被成功的激活l 驱动器经过测试二、 内存配置BSP负责配置主内存来实现快速的内核操作l 一些关键地址必须被定义l 如果使用MMU,必须定义内存映射l 提供支撑程序内存地址的定义在以下的文件中:-config.h-用户可配置的-.h-由目标板配置,非用户使用BSP提供的内存函数:sysMemTop()、sysNvRamSet()、sysNvRamGet()上图代表了下载的镜像被重定位后的RAM的分区;一个

3、WDB代理内存池仅仅当与VxWorks镜像一起的Tornado工具被使用时才需要;用户保留内存是不被VxWorks的程序所访问的。 char * sysMemTop(void)l 函数返回系统内存的首地址,代码在sysLib.c中;l 宏USER_RESERVED_MEM定义了不被VxWorks程序访问的用户保留内存的大小l 如果BSP不支持可选函数sysPhyMemTop(),由LOCAL_MEM_LOCAL_ADRS+ LOCAL_MEM_SIZE替代。l 内存的自动分区允许在初始化时配置物理内存的大小,如果自动分区功能没有激活,物理内存的大小由config.h中的LOCAL_MEM_SI

4、ZE静态定义;l 自动分区的具体细节是根据系统的不同而异的,典型的有:当DRAM在romInit()中被初始化时,配置信息存储在内存的控制寄存器或/和软件结构中;在分区时,配置信息被读取来计算所有物理内存的大小。l 支持自动分区的函数是sysPhysMemTop():char * sysPhysMemTop(void)函数返回的是物理内存的首地址;如果LOCAL_MEM_AUTOSIZE在config.h中被定义,该函数可提供动态的内存分区;BSP对自动分区的支持是可选的,如果参考BSP的代码没有静态的修改,被定义的缺省值将被返回;SysPhysMenTop()是由sysHwInit()函数调

5、用的:该函数必须在KernelInit()之前,也就是sysMemTop被调用时。内核激活的调用:l 所有的BSPs必须有NVRAM接口即使在目标环境中没有非易失RAM,接口必须支持:sysNvRamSet() 、sysNVRamGet()l 所有NVRAM的大小必须在config.h中定义为NV_RAM_SIZE的大小,如果没有NVRAM则定义为NONE;l 如果提供了,NVRAM用于存储可下载的镜像的启动参数;l 缺省配置在NVRAM的开头保留了255个字节用于启动参数的存储;l 缺省的启动参数在config.h中定义并静态连接到可下载的VxWorks的镜像中,缺省条件下是没有NVRAM的

6、;l NVRAM为启动参数分配的大小和定位在configAll.h中定义:BOOT_LINE_SIZE定义NVRAM为启动参数保留的大小,缺省为255字节;NV_BOOT_OFFSET定义了启动参数在NVRAM中的首地址,缺省为0;为覆盖缺省值,在config.h中重定义宏。l set/get NVRAM的程序部分驱动器在./src/drv/mem目录下,如果没有NVRAM使用./src/drv/mem/下的nullNvRam.c,该程序包含在sysLib.c中。l NVRAM支持的函数:STATUS sysNvRamSet(string,strLen,offset)STATUS sysNvR

7、amGet(string,strLen,offset)三、MMU机制l MMU主要是受系统库的控制,BSP则负责提供对物理内存描述符的支持:由MMU使用的物理内存描述符用来创建与虚拟地址空间的初始映射;缺省的映射是平滑的,一对一的在物理和虚拟内存空间的映射。l MMU由tUsrRoot任务调用usrMmuInit()进行初始化和使能首先初始化系统内存池的设置;其次是MMU的初始化;l MMU的支持可提供基本级别或通过可选产品VxVMI两种,本章主要讨论基本级:对基本的MMU支持,宏INCLUDE_MMU_BASIC必须在config.h中被定义;l UsrMmuInit() 的代码在./src

8、/config/usrMmuInit.c中l 初始的(静态的)物理内存映射定义在sysLib.c中,是定义在./h/vmLib.h中一个结构数组SYS_PHYS_MEM_DESC:l 映射的状态有:有效或无效、可写或不可写、可高速缓存或不可高速缓存l 虚拟-物理的映射举例:l 由结构库使用的配置宏用于初始化MMU的转换表;l 配置宏在./h/vmLib.h中定义l 修改物理-虚拟内存的映射:修改sysPhysMemDesc(静态映射),调用vmBaseStateSet()(动态修改);l 映射到一个页面的内存:页面的大小由宏VM_PAGE_SIZE在configAll.h中定义的,缺省为8k(

9、对PowerPC结构是4K),对sysPhysMemDesc映射的长度应该是页面大小的整数倍;l 每一张表的入口都需要一个物理内存的页表入口:为能定义多少地址映射设置一个上限;l 一些MMU也应该限制有多少内存能被映射,参考硬件的文档。l 虚拟内存映射必须映射所有的可被访问的物理内存,包括被映射的设备内存(Ethernet,SCSI, etc);l 当MMU使能时,对非虚拟物理映射的地址进行写操作时会导致总线错误;l 通常虚拟物理映射的配置有:Local RAM有效、可写、可高速缓存ROM有效、只读、经常高速缓存Flash有效、可写、非高速缓存I/O设备有效、可写、非高速缓存脱离目标板的内存有

10、效、可写、非高速缓存l 可编程Flash需要直接访问因此不能被高速缓存,但如果flash是只读的就可以被高速缓存;STATUS vmBaseStateSet(context,pVirtual,len,stateMask state)Context:映射的上下文,变量类型:VM_CONTEXT_ID;Pvirtual:被修改状态的虚拟地址,变量类型:void*;Len: 映射的长度,变量类型:int;StateMask:Unsigned int;State: Unsigned intl 该函数改变了一块虚拟内存的状态:用于改变由sysPhysMemDesc定义的初始内存映射;l 函数的第一个参数

11、为NULL时表示指示的是当前的context;l 虚拟映射对基本级的MMU是全局的,对于构造和管理私有context的信息请参照VxVMI;四、 速缓存Cache机制l 在VxWorks中,如果MMU使能,Cache就在MMU的控制下;l 系统库(cacheLib)中提供基本的cache管理支持,其中BSP的主要功能:选择合适的cache库和模式执行多个cache的操作;如果MMU使能,内存映射将被标识是否被cacheable;遵循设备驱动器的cache策略,对BSP控制的系统设备进行操作;STATUS cacheLibInit(intMode,dataMode)IntMode 定义指令cac

12、he的模式,类型:CACHE_MODEDataMode 定义数据cache的模式,类型:CACHE_MODEl 初始化cacheLib机制:调用结构定义的初始化函数;置cache为静态;在sysHwInit()运行之前由usrInit()调用。l 参数用来定义指令/数据caches的模式l CACHE_MODE 在./h/cacheLib.h中声明l Cache的模式配置宏:USR_I_CACHE_MODE ,USR_D_CACHE_MODEl 对cache模式配置的宏的确省值在configAll.h中定义。如果需要则在config.h中重新定义:l 对指令和数据的缺省模式是writethro

13、ughl cache模式由具体的cache库用来配置合适的cache硬件l 如果目标板支持多cache的操作,BSP负责选择恰当的库package:MACRO_ARCH_MULTIPLE_CACHELIB 必须在./h/arch/arch.h中定义为TRUE或FALSE;如果为TRUE则通过声明和初始化sysLib.c和config.h中的sysCacheLibInit提供正确的cache初始化;FUNCPTR sysCacheLibInit=(FUNCPTR) cacheXLibInit;l 对于L2 cache,BSP需要提供单独的cache管理库:l 系统支撑决定_ARCH_MULTIP

14、LE_CACHELIB是否定义为TRUE,BSP并不控制;STATUS cacheEnable(cache) cache:CACHE_TYPEl 使能特定的cache类型:指令、数据或者分支要使用特定系统的函数;l 必须undefine config.h中的宏来禁止:INCLUDE_CACHE_SUPPORT为任何cache的类型;USER_I_CACHE_ENABLE为指令Cache;USER_D_CACHE_ENABLE为数据Cache;USER_B_CACHE_ENABLE为分支Cachel 在usrInit()中被调用,在KernelInit()调用之前;l 缺省的所有Cache类型在

15、configAll.h中定义;l CACHE_TYPE结构在./h/cacheLib.h中声明;l Cache类型定义在./h/cacheLib.h中l 对管理有效访问设备的代码不论设备是否独立于BSP要保持cache与DMA设备和硬件寄存器的一致性管理设备内存访问方法防止RISC处理器的指令的无序操作l 使用cacheLib实行期望的cache管理为cache分配安全的缓冲区为一个驱动器(系统设备或BSP独立的设备驱动器)分配属性并且申请执行方法l 一些系统具有特殊的cache库,具体可参见VxWorks Reference Manuall 对设备cache的管理机制与被分配的可由设备访问的

16、内存大小有关l 可由设备访问的被分配的内存使用:cacheDmaMalloc(), malloc和memalign,数据段和堆栈段内存,系统区外的特殊内存区,未知的分配方法l 设备寄存器内存:如果内存被映射,将使用上述方法中的一种被分配;如果内存没有映射,将不被高速缓存;void * cacheDmaMalloc(bytes)bytes: 分配的字节数,变量类型:size_tl 函数为DMA设备分配了cache-aligned,cache-safe 的缓冲区,返回内存的首地址l cache对通过cacheDmaMalloc()分配的内存的一致性管理是依赖于MMU是否使能如果MMU使能,被分配的

17、内存被标为non-cacheable如果MMU不被使能,刷新和禁止的宏代码调用必须插入代码l cacheLib通过CACHE_FUNCS和CACHE_LIB结构(见。/h/cacheLib.h)来管理刷新、禁止和其他的宏程序,例如:l 宏代码使用CACHE_FUNCS和CACHE_LIB结构中的程序指针,例:l 通常情况下,如果一个特定的宏程序是一个no-op,它的CACHE_FUNCS和CACHE_LIB结构中的程序指针为NULL:所有的探查、刷新和禁止函数被设置为NULL;l 宏程序被分为两组:CACHE_DMA_XXXX 这些程序刷新、禁止和执行其他的通过cacheDmaMalloc()

18、分配的内存区域的操作CACHE_USER_XXXX 这些程序刷新、禁止和执行其他的不是通过cacheDmaMalloc()分配的内存区域的用户操作l CACHE_DMA_XXXX和CACHE_USER_XXXX宏定义使用低一级的宏程序CACHE_DRV_XXXXl CACHE_DRV_XXXX 宏允许在提供cache与独立的内存分配方法一致的灵活性:程序具有一个附加的指向CACHE_FUNCS结构的指针参数;l 开发者能够使用CACHE_DRV_XXXX宏来控制cache与驱动器控制的内存、可定制的cache管理的一致性STATUS drvDmaExample (void * pBuf)l C

19、ache对设备的策略将由使用的哪一个cacheLib机制来决定l BSP开发者应基于设备的属性来开发cache,属性有:WRITE_PIPING, SNOOPED, MMU_TAGGING, USER_DATA_UNKNOW, DEVICE_WRITES_ASYNCHRONOUSLY, SHARED_CACHE_LINES, SHARED_POINTERSl 属性将指示cacheLib将怎样被使用chapter 2 内存管理的实现一、vxWorks操作系统内存管理的库函数vxWorks提供了一个用于从内存池中动态分配、释放、重新分配内存块的工具。动态分配内存块可为任意大小;并且可自己指定内存池

20、的尺寸。这些内存管理机制的基础是vxWorks能管理好几块单独的内存池。(注:内存池与内存分区为同一概念)这些工具主要是用库函数的形式提供。MemPartLib库: 内核内存分区管理器该库提供了一些用来管理内存块分配的内核工具,所分配的内存块是在某一特定内存分区分配;也就是说先分配好内存分区,再在分区中分配内存块。该库中包含2套内存分配例程:一套为memPart.(),主要由创建和管理内存分区以及在某一个分区中分配和重新分配内存块的通用工具组成;另一套提供了与传统ANSI兼容的malloc()和free()接口,该接口主要用于系统内存分区中内存的分配和释放。其中系统内存分区在内核初始化时被创建

21、(内核在usrRoot()任务中,由kernelInit()函数初始化),系统内存分区的ID存储在全局变量memSysPartId中,该变量在memLib.h中被声明。在分配内存时,一般情况下调用malloc()函数用于在系统分区中分配内存;而调用memPartAlloc()函数主要是用于在特定内存分区中分配内存。所有内存的分配均采用首先拟合调度算法(在下面的章节中将有详细的说明)。在用memPartFree()函数和free()函数释放内存时,先检查相邻的内存块是否为空闲,如果为空闲则合并成一大的空闲块。该库同时提供memPartAlignedAlloc()例程在特定的内存分区中来分配与某一

22、规定边界对准的内存块(详细情况可参见函数参数的说明)。注意:不同体系结构有不同的对准限制,为了提供最优的性能,malloc()函数根据体系结构的不同返回一指向一个缓冲区的对准好的指针。缓冲区中可能有一部分空间不被使用。以下为该库中函数的说明:1创建内存分区:PART_ID memPartCreate ( char * pPool, /* pointer to memory area */ unsigned poolSize /* size in bytes */ )该例程用来创建包含在一指定内存池中的新内存分区。返回值为一分区ID,该ID可以被其它管理分区的例程使用(比如:在分区中分配内存块和

23、释放内存块例程)。创建分区的目的主要是为了管理彼此分开的内存池。2将内存池中一内存块加到一内存分区STATUS memPartAddToPool ( PART_ID partId, /* partition to initialize */ char * pPool, /* pointer to memory block */ unsigned poolSize /* block size in bytes */ )3从一内存分区中分配一块内存void *memPartAlloc ( PART_ID partId, /* memory partition to allocate from */

24、 unsigned nBytes /* number of bytes to allocate */ )4在一内存分区中释放一内存块STATUS memPartFree ( PART_ID partId, /* memory partition to add block to */ char * pBlock /* pointer to block of memory to free */ )5将一内存块增加到系统内存分区void memAddToPool ( char * pPool, /* pointer to memory block */ unsigned poolSize /* bl

25、ock size in bytes */ )6从系统内存分区中分配一块内存void *malloc ( size_t nBytes /* number of bytes to allocate */ )7释放一块内存void free ( void * ptr /* pointer to block of memory to free */ )MemLib库 具有特色的内存管理器该库为在内存分区中分配内存块提供了一些具有特色的工具。该库是memPartLib库的扩展,并且提供了一些增强的内存管理功能,包括:差错处理;对准分配;ANSI分配例程。该库中包含3个与ANSI兼容的例程:calloc(

26、)为一数组分配一内存块;realloc()改变指定内存块的大小;cfree()释放由calloc申请的内存,将其归还到空闲的内存池中。使用 memPartOptionsSet()和memOptionsSet()函数,可为每一分区选择多种调试选项。在分配和释放内存时,主要检测两种类型的错误:试图分配比可得的内存块更大的内存;在内存释放时,发现坏的内存块。在这两种情况下,错误状态将会返回。并且有4种错误处理选项可选。MEM_ALLOC_ERROR_LOG_FLAG在分配内存有错时,将一消息登记到日志中。MEM_ALLOC_ERROR_SUSPEND_FLAG在分配内存有错时,悬挂该任务。MEM_B

27、LOCK_ERROR_LOG_FLAG在释放内存有错时,将一消息登记到日志中。MEM_BLOCK_ERROR_SUSPEND_FLAG在释放内存有错时,悬挂该任务。1为一内存分区设置调试选项STATUS memPartOptionsSet ( PART_ID partId, /* partition to set option for */ unsigned options /* memory management options */ )2分配一对准内存void *memalign ( unsigned alignment, /* boundary to align to (power of

28、 2) */ unsigned size /* number of bytes to allocate */)3在页的边界分配内存void * valloc ( unsigned size /* number of bytes to allocate */ )该例程保证所分配的缓冲区在页的边界。页的尺寸与体系结构相关。4在一特定的分区中重新分配一块内存void *memPartRealloc ( PART_ID partId, /* partition ID */ char * pBlock, /* block to be reallocated */ unsigned nBytes /* n

29、ew block size in bytes */)。5找到最大可得的空闲内存块尺寸int memPartFindMax ( PART_ID partId /* partition ID */ )6为系统内存分区设置调试参数void memOptionsSet ( unsigned options /* options for system partition */ )7在系统内存分区中找到最大的空闲块int memFindMax (void)8为一数组分配空间void *calloc ( size_t elemNum, /* number of elements */ size_t elem

30、Size /* size of elements */ )9重新分配一块内存void *realloc ( void * pBlock, /* block to reallocate */ size_t newSize /* new block size */ )10释放一块内存STATUS cfree ( char * pBlock /* pointer to block of memory to free */)三、 OSS中的内存管理内存资源是系统重要的资源。为了节省和保护所需,根据实际情况将内存分为UB_SPAN,UB_SPAN*2,UB_SPAN*4,UB_SPAN*8 UBPOOL

31、_SIZE种大小,每种大小的内存用一队列来进行管理。并提供申请和归还的函数接口。为满足软件的不同需求,UB是可定制的,参数如下:UBPOOL_SIZE 表示UB_POOL的数量UB_SPAN 表示UB_POOL的粒度MAX_UB_SIZE 表示最大的UB大小内存队列是一个简单的循环队列,申请时从队列头取一空闲块,归还时归还队列尾。由于内存队列是系统的每个任务都会申请和归还的,设置了一个工作信号量来互斥。每个内存块都有一个头,头中记录有该内存块的地址,该内存块所属于的内存队列,申请指针与归还指针。头的地址值能防止将非法的内存归还到队列中,头中记录的内存队列使归还时可以无需进行查找,即知道该内存块

32、所属的队列,提高效率。申请指针是申请时填入的,归还指针是归还时填入的,两者配合起来可以查找内存的非法占用或长时间占用。内存申请算法:申请内存(VmGetUB)时,根据所需内存数值的移位,得到一级索引值,找到相应的UBPOOL及其对应的内存队列,根据队列的头, 将可用数据块的指针值返回给调用者。内存管理系统的初始化以及内存申请的算法如下图所示:内存初始化和内存申请算法chapter 3 一个内存泄漏定位实例在联调过程中,由于我们的设备必须长时间不间断运行,如果某个模块出现了内存泄漏,将会导致系统可用内存越来越少,最终导致系统瘫痪。本文对前几天MCU版软件出现的内存泄漏故障,以及故障的定位及解决办

33、法作了一个总结,供参考。故障现象:所有的NBAP消息编解码失败,原因是申请不到动态内存。分析及解决步骤:1、 首先判断是否是NBPS子系统引起由于故障的直接表现是在NBPS子系统,而且NBPS子系统使用动态内存很频繁,因此应首先判断是不是由于NBAP编解码部分引起内存泄漏。由于在此之前,NBAP编解码部分已经经过较长时间考验,在WINDOWS+VC平台长期运行,未发现内存泄露的现象;编解码部分的内存申请、释放都围绕编解码上下文进行(由购买的软件实现)。在此之前,NBAP编解码上下文的申请、释放都已经进行计数,而且经过长时间观察,释放与申请的个数完全一致。同时,观察内存泄露的规律,在较长时间未运

34、行编解码程序的情况下,也存在泄漏,因此可基本排除NBPS子系统。为了进一步确认,将NBAP编解码申请内存的函数该为了malloc,但是仍然存在内存泄漏。因此故障肯定在其他模块。2、 确定泄漏的内存块大小在采用OSS的环境中,例如MCU板,内存的分配、释放采用OSS提供的原语VmGetUB、VmRetUB实现。OSS管理的内存实在系统启动时一次性分配好的,根据实际系统的需求,将一次性申请到的内存划分为大小不等的内存池,每个内存池管理不通大小的内存块。内存的信息保存在全局数组atUBPool中。系统提供了函数QueueSize来获取某一个内存池中还可以分配的块数。通过检查系统的内存池中身下的内存块数量,可以确认系统是否存在内存泄漏,并定位哪一个内存池出现了泄漏。例如,我们可以写如下的函数:void ShowUB()BYTEbyLoop; for ( byLoop = 0; byLoop UBPOOL_SIZE ; byLoop +)printByUdp(9, UB pool %d Queue size=%d.n,

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论