天天看点

Windows Embedded CE6.0高效的内存管理

作者:Douglas Boling 时间:2007年3月 本文来自:微软MSDN技术论文中心

     本文主要介绍新版本嵌入式操作系统(Windows Embedded CE6.0)是如何管理内存的,内容主要包括如何构架以及在应用程序发生的变化两个部分。

     在过去的10年里,Windows Embedded CE操作系统已经从一个非成熟的操作系统发展成一个新的、有活力的操作系统。当然,Windows Embedded CE始终是一个先进的、抢先多任务和支持虚拟内存的操作系统,,在这段发展过程当中,微软在Windows embedded CE操作系统除内存管理外的各个方面都进行改进,但、Windows Embedded CE操作系统却在一些领域因为内存和代码密集因素受到一些严格的限制,例如机顶盒领域。

      具体来说,这些限制是Windows Embedded CE操作系统最多支持32个进行并发,每个进程最对只有32MB虚拟内存。这些限制方面的问题仅仅只出现在前期版本的Windows Embedded CE操作系统当中,在现今的其他嵌入式操作系统当中也存在。为了减少进程数量,系统往往将许多应用程序如Windows Media® player集成到系统程序中实现,这导致整个系统和应用程序代码庞大,如此,往往还需大量的小程序来控制集成到系统中的应用程序。

      由于采用了完全重写新的操作系统内核和架构,Windows Embedded CE6.0从此打破了“两个32时代”。新内核支持32000个进程并发,我们可以相信在数年内32K进程并发支持都不会再受到限制。另外应用程序的虚拟内存也得到了改善,从原先的32MB提升到了2G的虚拟内存空间。

      为了帮助完全理解Windows Embedded CE新内核做的改善,我们先来重新展示Windows Embedded CE5.0操作系统的内存结构。图1.1为Windows Embedded CE5.0的虚拟内存结构。如同Windows® XP 和 Windows Embedded CE6.0一样,Windows Embedded CE5.0的前2G的内存为操作系统本身预留的,后半部分(低地址段)被分成很多个区域,每个区域32MB。另一半最大的区域,分配了大块的内存,常常分配给内存映射文件使用。

Windows Embedded CE6.0高效的内存管理

图 1. 1 Windows Embedded CE5.0虚拟内存结构

      下面的大块内存被分成了31个Slot,其中包括正在运行进程的虚拟内存结构,下面这些进程Slot,每个进程的最大内存空间只有64MB。更确切的说,最低的32MB区域是分给当前运行的程序,其中包括也这个进程建立线程。

      这样的“Slot结构”导致32个进程和32MB虚拟内存的限制。因为这31个Slot限制了进程并发的数量,包括系统,不能操作32,计算下,当你将这32个进程并发运行在系统当中所需的内存就已经到了2G了。

      如图1.2所示最低64MB Windows Embedded CE的虚拟内存空间。其中低32MB是用来从当前正在运行的进程中的线程中复制其被分配的内存空间。高32MB用来加载代码和存储在只读ROM-Based的动态链接库,高32MB被视为“Slot1”,被所有的运行的应用程序所共享。

      每个Slot的大小导致32MB的限制,由于单一的,传统的内存空间,如果使每个进程的虚拟内存变得更大些,这将减少Slot的数量,从而减少并发进程数量。正是因为内存大小(32MB)和进程数量(32个)都做了相应的妥协才保证系统的能更好的工作。

Windows Embedded CE6.0高效的内存管理

图 1. 2 最低64MB Windows Embedded CE的虚拟内存空间

      Windows Embedded CE6.0新的内存结构如图1.3所示。采用这种新的内存结构,每个应用程序可以最多分配到2G的虚拟内存空间,虽然这2G的空间表面上类似Windows XP操作系统,但是每个应用程序使用相同的虚拟地址空间布局似乎是不同的。

      图1.4显示了Windows Embedded CE6.0中每个进程的虚拟内存空间分配结构。像早期的Windows Embedded CE6.0一样,2G的虚拟内存空间被分成两部分。其中低1G空间用于加载代码和动态分配内存,这里所有分配的内存都被本配到进程中相关线程堆栈的位置。

      刚刚越过这个区域的一个512MB的区域,用于加载系统代码和所有应用程序需要的存储在只读ROM-based的动态链接库。像以前版本的Windows Embedded CE操作系统一样,每个被应用程序加载的DLL都被加载到所有进程加载这个DLL的相同地址位置。这个DLL从这个区域的底部地址(0x40000000)开始,不是自上而下方式,具体要视不同版本的Windows Embedded CE而定。

Windows Embedded CE6.0高效的内存管理

图 1. 3 Windows Embedded CE6.0新的内存结构

      越过DLL区域,从0x60000000开始,是一个256MB空间。这段空间用于分配RAM-backed内存映射文件。分配RAM-backed内存映射文件也被视为内存映射对象,没有一个实际的文件支持的对象数据。内存映射对象常用于进程间通讯。为了方便向后兼容,如果一个名为内存映射对象是在多个进程分配,系统将为这些内存映射对象分配相同的地址。如果一个进程打开一个内存映射访问实际的文件,则该内存映射文件缓冲区将被分配在应用程序虚拟地址的空间的低1GB的空间中。

      在虚拟地址0x70000000后的256MB的区域是用于操作系统和应用程序通信,对应用程序来说,这部区域只读,对操作系统来说,这部分可读可写。最后,其中0x7FE00000开始的1MB空间是一个警戒区,操作系统和应用程序都无访问权限。

      总之、在Windows Embedded CE6.0中,应用程序有1G的虚拟地址空间用于加载代码和内存分配,另外的1GB空间用于专用用途。虽然虚拟内存空间只有一半是可用的内存分配,它比以前的32 MB的Windows Embedded CE5.0要好的多了。另外,由于Windows Embedded CE 6.0中保留了512 MB的物理的限制,我猜测操作系统在一个应用成熟释放完成虚拟内空间之前就已经释放了物理RAM空间。

Windows Embedded CE6.0高效的内存管理

图 1. 4 Windows Embedded CE6.0中每个进程的虚拟内存空间分配结构

      图1.5为Windows Embedded CE6.0内核虚拟地址的内核分配图。以早期版本的Windows Embedded CE6.0操作系统一样,这首两个内核地址空间区域分别是在物理地址空间上的缓存和非缓存窗口。通过这些窗口操作系统和驱动能访问到RAM和内存映射的外设当中。

Windows Embedded CE6.0高效的内存管理

图 1. 5 Windows Embedded CE6.0内核虚拟地址的内核分配图

      在地址0xC0000000后的128MB的区域中分布被内核加载的ROM-based动态链接,下一个0xC8000000开始的128MB区域存储映射到RAM-based对象的文件系统。

      从0xD0000000开始就是内核虚拟机空间。这个区域正是系统的内核模式制定的地方。内核、所有的操作系统的扩展(像FileSys、GWE和运行在内核态的设备驱动)都被加载到这个区域。这个区域的大小依据采用的CPU而定。除sh4是256MB外,其他所有的CPU都是512MB。最后、从0xF0000000开始的区域被用于特定的CPU专有用途。

       新的内存分配方式比起前期的Windows Embedded CE操作系统发生很大的变。为了更清晰的认识这巨大的变化,接下来让我们谈谈Windows Embedded CE操作系统是如何构架。

      正如内存讨论的一样,这充分的展示了Windows Embedded CE6.0内核发生了巨大的变化。我返回Windows Embedded CE5.0看他们是如何构架。从一开始,Windows Embedded CE一直维绕这用户模式程序设计被称为PSLs。虽然内核程序,NK.exe操作在内核模式,操作系统的其他部分如文件系统、设备管理、图形子系统都被独立分开。用户模式只用文件名FileSys.exe、Device.exe和GWES.exe加以区分。

      这些单独的进程所作的操作系统强劲,因为来自主要子系统相互保护,但在性能为代价。一个函数调用操作系统造成至少1和可能两个进程开关。除此之外,受到32MB限制的Windows Embedded CE操作系统限制了所有的进程。

      Windows Embedded CE6.0内核屏蔽了独立的进程,并把所有的进入内核的进程运行在虚拟机子系统中。这一变化提高了操作系统的性能,因为各子系统之间的沟通现在是一个简单,内部调用即可。如图1.6所示Windows Embedded CE操作系统的结构。

      注意早期版本中的子系统(FileSys,Device,和GWES)现在是DLLs。另外、内核代码也由原来的NK.exe变为现在的Kernel.dll。新的NK.exe只包含OEM抽象层代码和一个非常小的兼容层。这种分离会改善可维护性,因为内核更新,只需更新OEM代码即可。

      现在设备管理在内核虚拟机里面实现,大多数的设备驱动也集成在里面。在以前版本的Windows Embedded CE,设备管理器只有在系统重启和有需要后才加载驱动程序,它们都运行在客户模式,现在所有的设备驱动都运行在操作系统内核态。

Windows Embedded CE6.0高效的内存管理

图 1.6 Windows Embedded CE操作系统的结构

      然而运动都运行在内核虚拟机里面,这意味着将OMEs一直到6.0版本将是一个很大哦的工程,并迫在眉睫。但是移植其实很简单,关键的任务是k.Coredll.dll动态库。他和个动态库被命名为新的名字Coredll.dll,它一直驻留在用户模式下,像用户态程序提供对应的内核态API,例如VirutalAlloc函数。对于应用程序来说,k.Coredll.dll只反映Kernel.dll调用接口。因为这些调用都是在相同的虚拟机中完成的,这个时候调用VirutalAlloc函数Windows CE5.0后以前的操作系统要简单多了。

      Coredll.dll不仅仅去掉k.Coredll.dll链接库中的"K",任何一个DLL想要在用户和内核模式被调用,那么这个DLL需要在用户和内核模式都被加载。由于在Windows Embedded CE6.0为每一个实例化的DLL都保持了一个固定的地址,且在DLL名称前加一个"K"来进行重新命名。

      实际上有些驱动程序不应该加载到内核虚拟机里面,例如第三方的驱动是在设备实例化之后才进行安装的。Windows Embedded CE6.0提供了一个用户模式的驱动管理管理器,它将加载这些驱动到用户模式。用户模式的驱动与应用程序的通讯应该尽量减少,除非改善了安全机制。

      在Windows Embedded CE6.0和以前的其他版本的驱动几乎一样的方式支持。和以前一样,Windows Embedded CE6.0的服务被放置带用户模式,有服务管理器统一加载。除了注册表外,他们的设计一点没变,以前的Windows Embedded CE5.0服务只需更改注册表就可以在6.0平台下运行。

      虽然新的框架看起来很有意思,但是到多数程序员读到这篇文章可能会很惊讶“这些改变对我的应用程序意味着什么?” 幸运的是新系统的改变将应用程序变得更加成熟、更加好的处理效果。

      首先、让我们来回顾一下以前的老问题。Windows Embedded CE操作系统由于DLL文件占用了太多的进程虚拟内存空间导致被很多年被程序员们所唾弃。一些小的应用程序虚拟机空间,一直有些Windows Embedded CE加载的DLLs用于适合一些系统规则。现在新的系统,2G的地址空间,“DLL 破碎”的问题已经成为过去。

      另一个大内存空间的效果,系统保留的虚拟内存数量被用光之后,虚拟内存跑飞的问题。实际上,系统程序员担心应用程序在用完虚拟机空间之前已经用完了物理RAM的那块虚拟机空间。在6.0中这个问题消失了,Windows Embedded CE6.0宁愿为分配更多的RAM比以前的本版的系统,以防止VM强制移除、内配的内存瞬间达到可用的空间。

      Windows Embedded CE2.12以后的版本系统的一个标准特性是系统采用的安全手段。在这个体系中,模块(可执行文件和DLL文件)在加载的时候都被检测。OEM代码可以决定系统将这个模块加载到信任还是非信任模式。如果这个模块运行在可信模式,它能访问系统的API。如果模块的代码加载到非信任区将不能访问系统的一小部分关键的API和不能设置任何线程的优先级高于第8个最低的优先级。OEM甚至能告诉系统不要加载某个模块。

      Windows Embedded CE5.0和以前的版本有一个特殊的模式,在这个模式下,系统能运行所有的代码运行在内核模式,替代内核代码只能运行在内核模式下,系统剩下的部分只能运行用户态。由于内核代码和内存空间能访问所有的应用程序,因此在使用特殊模式的时候,应该权衡下安全性能。

       Windows Embedded CE6.0抛弃了上述的特殊模式和可行模式,特殊模式已经不需要了,因为在新的内核架构中大多数都能获得进入特殊模式的能力。在后期的Windows Embedded CE版本中将用桌面安全访问控制列表来替代可信模型,但是在Windows Embedded CE6.0中完全抛弃了可信模型和安全控制列表。

       Windows Embedded CE6.0和早期的一些版本提供了一样的进程间通信方式。这些方式包括RAM-backed内存映射文件,敌对点消息队列和传统的WM_COPYDATA消息机制。

      利用“Slot based”通信方式已经在Windows Embedded CE6.0行不通了。有些应用程序用MapCallerToProcess和SetProcPermissions试图去读写进程内部的内存。这两个函数有几个其他的函数依赖与“Slot模型”外,其他一点关系都没有。如果你从Coredll.dll中到处了用于兼容的函数,那么在Windows Embedded CE6.0中用这两个函数是一点问题都没有。

      另外一个Windows Embedded CE6.0的改变是在也不能拷贝句柄到另一个进程中。CE6.0是将每一个进程的句柄表分开。如此句柄值只依赖于每一个进程本身。为了去解决这个问题,应用程序可以用DuplicateHandle函数从其他进程克隆句柄。

      总体来说,写好的Windows Embedded CE应用程序(不能用Slot-based方式)可以无需修改就可以运行在Windows Embedded CE6.0系统中,为了确保应用程序能够运行,你应该在Windows Embedded CE6.0 Platform Builder中加入兼容的测试工具。

       Windows Embedded CE6.0对于Windows Embedded CE系列来说是一个巨大的提高。传统内核限制的消除将较少为了解决这个问题特增加的帮助程序。新的内存管理模式将使得Windows Embedded CE更加接近于XP桌面模型,但是内核尺寸和开销还是不同。期待下一步能看到一款全新的强悍的设备驱动模型,和更好的Windows Embedded CE版本。

申明:本文为作者原创翻译,转载必须获得博主同意,否则侵权.

继续阅读