天天看点

Windows Embedded CE&nb…

一、Windows Embedded CE 6.0的内存管理模型

与以前版本的Windows CE相比,Windows Embedded CE 6.0的内存管理模型有了很大的变化,这主要体现在Windows Embedded CE 6.0的虚拟地址空间不再是一个4GB平面架构模型,而是一个如图1所示的立体架构模型。虽然Windows Embedded CE 6.0所能访问的线性虚拟地址空间仍然为4GB(232),所有进程共享一个唯一的2GB的内核空间,但对于2GB的用户空间来讲,却不再由所有进程来共享,每个进程只占用32MB的虚拟地址空间,而是每个进程独占2GB的用户空间,且可以有32K个进程同时运行。这样,每个进程所占有的虚拟地址空间就由原来的32MB提高到了2GB,同时可运行的进程数也由原来的32个一下子提高到了32768个。

需要注意的是,尽管Windows Embedded CE 6.0的虚拟内存模型是一个立体的架构,但在某一时刻,由于只能有一个进程在活动,这样,这个活动进程所占用的特定的2GB的用户空间就与2GB的内核空间共同组成了一个4GB的线性虚拟地址空间。每个用户进程有自己唯一的内存映射,多个用户进程之间不会产生冲突。同时,不允许用户进程访问内核存储器区域,但位于内核区域的组件却有权访问整个4GB的地址空间,且可以访问任何有效的存储器位置。

Windows Embedded CE&nb…

图1  Windows Embedded CE的虚拟地址空间

Windows Embedded CE 6.0是一个32位的保护模式的操作系统,操作系统对于任何存储器地址或空间的访问都必须是对虚拟地址的访问,而物理地址都是不可直接访问的,任何物理地址都必须在被映射为虚拟地址之后,操作系统才能进行访问。物理地址到虚拟地址的映射有两种方式,一种是静态映射方式,一种是动态映射方式,静态映射为内核提供了一个虚拟地址到物理地址的静态映射表,这个映射表在系统引导时创建且不随时间而变化。OEMAddressTable定义了ARM和X86 CPU的这种静态虚拟地址与物理地址的映射,而对于SHx和MIPs处理器,CPU控制虚拟地址到物理地址的静态映射。动态映射是一种在需要时分配内存分页、在不需要时释放内存分页的一种虚拟地址到物理地址的映射,由于动态映射限制了由MMU所使用的映射表所需要的物理内存量,因此可以节省内存资源,有效地使用物理内存。

图2是物理内存与虚拟内存静态映射的一个例子,从图上可以看出,物理内存被同时映射到两个不同的虚拟地址空间,一个是被标记为缓冲(Cached)的512MB的虚拟地址空间,另一个是被标记为非缓冲(Uncached)的512MB的地址空间。在虚拟内存模型架构中,使用MMU来完成物理地址到虚拟地址的映射,但MMU的作用不仅仅如此,映射操作也包含一些允许进行什么样的访问(如读、写、执行或不允许访问等)的信息,也包括为了完成一个访问需要什么样的CPU模式以及访问是否使用缓冲等。在每次映射中,相同的物理内存可以被映射到具有不同访问能力的不同虚拟地址。对标记为Cached的虚拟地址的访问,CPU将直接访问Cache(缓冲区),而忽略与其对应的物理地址,这样可以获得更快的访问速度;而对标记为Uncached的虚拟地址的访问,CPU将跳过缓冲区,直接访问与虚拟地址对应的物理内存。由于Cache是位于CPU内部更快速的物理存储器,CPU对它的访问速度将远远大于对扩展SDRAM及外设的访问速度。通常,如果一段RAM、SDRAM只有CPU访问,那么应该使用Cached地址,这样能获得最快的速度;而如果这段地址CPU与外设都会访问,则必须使用Uncached地址,这样CPU与外设的数据才能同步。对硬件设备寄存器地址的访问是使用Uncached地址对硬件进行读写访问的一个最常见的例子。

Windows Embedded CE&nb…

图2  物理地址与虚拟地址的映射

 二、 内核存储器空间

内核存储器空间是Windows Embedded CE 6.0虚拟地址空间中上面2GB的部分,在操作系统运行的整个过程中,对于所有进程它总是驻留的,它包含了提供更多基本操作系统服务的组件。内核空间详细的虚拟存储器映射如图3所示,对每个存储器区域的详细描述如表1所示。

Windows Embedded CE&nb…

图3  内核存储器空间

表1  内核存储器空间描述

范围 大小 描述 说明
0xF0000000 - 0xFFFFFFFF 256MB 特定于CPU的虚拟内存 系统调用捕获区域,内核数据页
0xE0000000 - 0xEFFFFFFF 256MB CPU相关的内核虚拟内存 内核空间虚拟内存(除非CPU不允许,如SHx)
0xD0000000 –0xDFFFFFFF 256MB 内核虚拟内存 内核空间虚拟内存,由所有的内核服务和加载在内核的驱动程序共享
0xC8000000 - 0xCFFFFFFF 128MB 对象存储 用于存储文件系统、CEDB数据库和注册表
0xC0000000 - 0xC7FFFFFF 128MB 内核XIP DLL 用于所有加载在内核中可就地执行(eXecute In Place)的DLL,包括内核服务器和驱动程序等
0xA0000000 - 0xBFFFFFFF 512MB 静态映射(Uncached) 跳过CPU Cache直接访问物理内存
0x80000000 - 0x9FFFFFFF 512MB 静态映射(Cached) 通过CPU Cache访问的物理内存

三、用户存储器空间

用户存储器空间是Windows Embedded CE 6.0虚拟地址空间中下面2GB的部分,这2GB的存储器空间对于每个进程都是唯一的,即每个进程都独占自己2GB的存储器空间。用户空间详细的虚拟存储器映射如图4所示,对每个存储器区域的详细描述如表2所示。

Windows Embedded CE&nb…

图4  用户存储器空间

表2  用户存储器空间描述

范围 大小 描述 说明

0x7FF00000 -

0x7FFFFFFF

1MB 未映射的保留区域 内核空间与用户之间的缓冲区

0x70000000 -

0x7FEFFFFF

255MB 共享的系统堆 内核与进程间的共享堆。内核和内核服务可以在此分配并进行读写操作;而用户进程只能进行读操作。这使一个进程不必进行内核调用就可以从内核服务获得数据

0x60000000 -

0x6FFFFFFF

256MB RAM后备的映射文件 RAM后备的映射文件被映射到固定的位置。通过调用函数CreateFileMapping并为hFile参数传递INVALID_HANDLE_VALUE值来创建或获得

0x40000000 -

0x5FFFFFFF

512MB 用户模式的DLL代码和数据 DLL由地址0x40000000开始向上加载;代码和数据是相互交叉的;由多个进程加载的一个DLL在所有进程中都被加载到同一个地址位置;对于每一个进程,数据页有唯一的物理页

0x00010000 -

0x3FFFFFFF

1GB 进程用户可分配的虚拟内存区域 可执行代码和数据;用户虚拟内存(堆)从exe之上开始并向上分配

0x00000000 -

0x00010000

64KB CPU相关的用户内核数据 用户内核数据对于用户总是只读的,而对于内核有可能是可读可写的(对于ARM CPU),也可能是只读的(对于其它CPU)

在Windows Embedded CE 6.0中,当一个进程初始化时,操作系统映射下列DLL和内存组件:

l         一些可就地执行(XIP)的动态链接库(DLL)

l         其它可就地执行动态库(XIP DLL)的一些读/写区域

l         所有不能就地执行的DLL(non-XIP DLL)

l         栈(Stack)

l         堆(Heap)

l         进程的数据区域

在进程初始化时,DLL和ROM DLL的读/写区域被加载在从底部向上1GB开始的虚拟存储器空间,对于每个进程来讲,所有的DLL都被加载到相同的地址。同时,栈、堆和可执行文件(.EXE)在进程初始化时被创建并从地址空间的底部64K以上的空间开始被一一映射,而底部64K的范围总是保持为自由存储器空间。

RAM后备的映射文件也被称为内存映射文件,是一种把文件直接当作系统内存来使用的方法,这样既避免了使用文件I/O对文件进行访问的麻烦,又可以用来在多个进程间共享数据。尤其是对于几十兆甚至几百兆的大型文件,这种方法提供了一种直接映射存取的方便之道。当任何进程打开同一个RAM后备的映射文件时,都会获得相同的指针值,因而,RAM后备的映射文件的用户存储器区域为使用RAM后备的映射文件来进行进程间通信的应用程序提供了一种向后的兼容性。与RAM后备的映射文件相对的是文件后备的内存映射文件(File backed memory map files),文件后备的内存映射文件是从进程的虚拟内存空间区域分配的,因而对于不同的进程是不同的,进程间不能共享。

堆是专门为应用程序保留的一部分内存,应用程序可以以每次一个字节或每次4个字节的方式分配和释放这部分内存,同样,应用程序也可以在堆中简单地分配一个虚拟内存块,而让操作系统去决定到底需要分配多少物理内存页。在Windows Embedded CE 6.0中,每个应用程序在被加载运行时,操作系统都会为它创建一个默认的、大小为64KB的本地堆。除了本地堆,应用程序还可以创建私有堆、共享堆和远程堆。如果应用程序要在本地堆中分配一个大于64KB的内存块,系统会通过调用VirtualAlloc函数来满足对内存的要求。应用程序也可以创建任意数量的单个的私有堆,这些私有堆除了由一组单独的堆函数管理外,与本地堆具有相同的属性。共享堆允许内核模式的组件有效地传输数据给用户进程,且对于内核组件共享堆是可读可写的,而对于用户进程却是只读的。共享堆位于用户地址空间之上的位置,对所有用户进程都是可见的,因此要避免将一些敏感数据放入共享堆。远程堆是Windows Embedded CE 6.0的一个新特征,远程堆允许一个服务器与客户端进程安全地共享内存,服务器进程负责创建远程堆,并对远程堆有完全的访问权,而客户端进程只能读或有选择地写远程堆,且不能销毁远程堆中的元数据。

栈也是专门为应用程序保留的一部分内存,用于保存需要先进后出(FILO)或后进先出(LIFO)的数据。堆是由进程分配的,而栈是由线程分配的;每个进程至少有一个堆,而每个线程只有一个栈(如图5所示)。栈的大小是在应用程序编译时确定的,而栈的分配却是在线程创建时分配的。默认情况下,一个进程的所有线程具有相同的栈大小。栈的大小可以通过/STACK链接开关来指定,一个单独的线程也可以动态地创建唯一的栈大小。

Windows Embedded CE&nb…

图4-8  堆和栈之间的关系