我是靠谱客的博主 坚定黑夜,最近开发中收集的这篇文章主要介绍Windows Embedded CE6.0高级内存管理,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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

 在Windows CE5.0和之前的版本中,整个系统(不是每个进程)使用一个4GB的虚拟地址空间,将高端地址空间(0x8000 0000~0xffff ffff2GB)划分给操作系统,把低端地址空间(0x0~0x7fff ffff2GB)划分给用户空间(应用程序),并且所有的应用程序共享(进程)共享这2GB的虚拟地址空间。用户地址空间的低1054MB0x0~0x41ff ffff)又被划分为33个槽(Slot),每个槽占有32MB的虚拟空间,其中Slot0保留给当前运行的进程(拥有CPU的进程),Slot1保留给就地执行(XIP)的DLLSlot2~Slot33WinCE系统中每个进程保留。当一个进程执行时,内核就将该32M进程空间映射到Slot0



与以前版本的Windows CE相比,Windows Embedded CE 6.0的内存管理模型有了很大的变化,这主要体现在Windows Embedded CE 6.0的虚拟地址空间不再是一个4GB平面架构模型,而是一个如图1所示的立体架构模型。虽然Windows Embedded CE 6.0仍使用4GB的虚拟地址空间,并将2GB高端地址的划分给操作系统,2GB的低端地址划分给用户空间,但对于2GB的用户空间来讲,却不再由所有进程来共享,而是每个进程独占2GB的用户空间,且可以有32K个进程同时运行。这样,每个进程所占有的虚拟地址空间就由原来的32MB提高到了2GB,同时可运行的进程数也由原来的32个一下子提高到了32K个。


 尽管Windows Embedded CE 6.0的虚拟内存模型是一个立体的架构,但在某一时刻,只有一个进程处于活动状态。这样,这个活动进程所占用的特定的2GB的用户空间就与内核所占用的2GB空间共同组成了一个4GB的线性虚拟地址空间。每个用户进程有自己唯一的内存映射,多个用户进程之间不会产生冲突。用户空间的进程不允许访问内核地址空间,

但位于内核空间的进程或组件可以有权访问整个4GB的地址空间,且可以访问任何有效的物理存储器。

Windows Embedded CE 6.0是一个32位的保护模式的操作系统,内存管理器MMU不仅完成虚拟地址和物理地址之间的映射,还要防止用户空间进程的非法访问。一旦MMU开启之后,操作系统对于任何存储器地址或空间的访问都必须是对虚拟地址的访问,而物理地址都是不可直接访问的,任何物理地址都必须在被映射为虚拟地址之后,操作系统才能进行访问。物理地址到虚拟地址的映射有两种方式,一种是静态映射方式,一种是动态映射方式,静态映射为内核提供了一个虚拟地址到物理地址的静态映射表,这个映射表在系统引导时创建且不随时间而变化。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 6.0虚拟地址空间中上面2GB的部分,在操作系统运行的整个过程中,对于所有进程它总是驻留的,它包含了提供更多基本操作系统服务的组件。内核空间详细的虚拟存储器映射如图3所示,对每个存储器区域的详细描述如表1所示。


图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所示。


图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的本地堆。

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

 

 

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

四、进程间通信

Windows Embedded CE6.0提供了与之前版本相类似的进程通信方法,这些方法包括共享RAM虚拟内存文件、点对点消息队列、WM_COPYDATA消息等。

Windows Embedded之前的版本中,应用程序可以调用MapCallerToProcess 和SetProcPermissions 系统API函数来对不同的进程空间进行读与写操作,这两个API函数以及一些其他相类似的函数均是基于槽(Slot)内存模型,但是在Windows Embedded CE6.0中已经不再支持基于槽(Slot)内存的进程通信方式,权宜之策是用ReadProcessMemory 、WriteProcessMemory 等API函数来代替之前的SetProcPermissions函数。

Windows Embedded CE6.0的另一个变化就是,在程序中不能将句柄从一个进程复制到另外一个进程。CE6.0为每一个进程创建了一个句柄表(Handle Table),在每个进程中句柄的值都是独立的,但是可以利用DuplicateHandle函数来为另一个进程克隆一个句柄。

最后

以上就是坚定黑夜为你收集整理的Windows Embedded CE6.0高级内存管理的全部内容,希望文章能够帮你解决Windows Embedded CE6.0高级内存管理所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部