【IT168 专稿】近几天,我在开发一款嵌入式移动产品项目上遇到了一点麻烦。这个应用是ARM9内核和WinCE平台,这几天我一直被纠缠在一个内存问题,程序吃内存很厉害,跑一段时间后,内存占用就接近100%了,出现所谓的假死机。
看任务管理器里面的程序内存使用一直都很正常,但整个系统的内存却在被缓慢的侵蚀,但就是看不出来是程序哪一部份使用了过多的内存。反复的查程序,也没发现内存泄漏,需要不断的修改内存分配策略,很头疼。
1.WinCE是如何分配内存?
(1)WinCE内存环境
在PC上增加物理内存是很方便的,插上内存条后只要自检程序识别,桌面操作系统就能够支持,而在基于WinCE的产品上就没那么简单了。嵌入式设备与桌面PC的一个显著不同是它的应用程序中通常需要直接访问某一段物理内存,这在驱动程序中对物理内存的访问尤为重要。尤其是像ARM体系结构下,I/O端口也被映射成某一个物理内存地址。而且与桌面版本Windows相比,WinCE也提供相对简单的物理内存访问方式,无论是驱动程序还是应用程序都可以通过API访问某一段物理内存。
一般来说,运行一个WinCE需要ROM(只读存储器)和RAM(随机存储器)。但在WinCE系统中,ROM和RAM的使用还是稍微有些不同于个人电脑环境。RAM在WinCE 系统中被分为两个区域:第一个是程序存储区(Program Memory),也叫做系统堆(System Heap),程序存储区有点像个人电脑中的RAM,它为正在运行的应用程序保存堆和栈的内容。第二个是对象存储区(Object Store),它有点像一个永久的虚拟RAM磁盘。不同于PC上的虚拟RAM磁盘,对象存储区保留存储的文件甚至可以在系统被关闭以后。
在WinCE系统中,存储在ROM的程序能以现场执行(Execute in Place,XIP)的方式运行。换句话说,程序可以直接从ROM中执行而不必先加载到RAM中再执行。这种能力对嵌入式系统来说,具有两个方面的巨大优势,一是代码直接从ROM中执行意味着程序代码不会占据更有价值的RAM;二是程序在执行前也不必先复制到RAM中,这样就只需要很少的时间来启动一个应用程序。而不在ROM中的但是被包含在对象存储区或闪存卡中的程序将不能以现场方式执行,它们将被复制到RAM中再执行。
(2)虚拟内存
电脑中所有运行的程序都需要经过内存执行,如果执行的程序很大或很多,就会导致内存消耗殆尽。为了解决这个问题,Windows运用了虚拟内存技术,以缓解内存的紧张。和大多数操作系统一样,WinCE也实现按需调页的虚拟内存机制。WinCE是32位的操作系统,支持4GB的虚拟地址空间。系统调用虚拟内存API来为其它类型内存分配内存,包括堆和栈。WinCE虚拟内存页可以处在三种状态:自由(free),保留(reserved),或被提交(committed)。
WinCE提供两种虚拟地址映射方法,分别为静态映射和动态映射,静态映射的虚拟地址空间只能由内核访问,而动态映射的地址空间可以由用户模式的应用程序访问。WinCE系统使用微处理器的内存管理单元(MMU)来处理虚拟地址和物理地址间的实时转换。意思是说:一旦WinCE系统的MMU开始工作,CPU就不再直接访问物理内存了,对于运行在x86和ARM系列CPU上的CE内核来说,必须先确立物理内存地址和虚拟内存地址的映射关系。
这种关系是在一个名为OEMAddressTable的表中定义的,属于静态映射方法。因此,在一个虚拟内存系统中,应用程序主要处理这个虚拟的地址空间,并不涉及到由硬件管理的物理内存,应用程序使用虚拟内存不需要知道实际物理内存的位置,只要有内存可用就行。