Windows CE中的内存管理

一、RAM和ROM

尽管Windows CE系统主要用在嵌入式系统上,且需要更加高效、节省地使用物理内存,但在Windows XP和Windows Me中采用的内存管理API函数被几乎完整的保留下来。

Windows CE设备一般没有磁盘驱动器,它的内存通常是由RAM和ROM组成的。

Windows CE中的RAM分为程序区(也叫系统堆)和对象存储两个区域。其中的对象存储区域可以被看做一个永久的虚拟RAM盘。和传统的PC机不同,Windows CE中的对象存储在系统关闭以后仍旧可以保存文件。因为在我们关闭电源的时候,系统并没有真正关闭,而是进入一个低功耗的运行模式。RAM的另一个区域就是程序区,这个区域就跟PC机的RAM一样。

Windows CE系统被设计为主电池和备份电池的双电池策略。

ROM称为“Read Only Memory”。Windows CE中,存储在ROM中的程序可以被设计成本地执行(XIP:Execute in place)。该方式可直接在ROM中运行,不像一般的程序运行方式,即无须释放到RAM中再执行。但XIP方式中,ROM的CPU访问速度较慢,实时性较差。

需要注意的是,存储在闪存(Flash Memory)中和对象存储区(Object Store)的程序不能被本地执行,必须拷到RAM中,然后再运行。

实际的应用中,如Pocket PC在出厂时已经将操作系统和一些应用软件安装到ROM中,而我们自行安装的软件则通常会在RAM中。为防止RAM中的数据丢失,微软公司在Pocket PC中安装一个叫做“Backup”的程序,它会将安装好的程序备份到内置的SD卡或者CF卡中,断电充电后可通过这个程序完全恢复过来。另外,Pocket PC中的RAM可以动态地调整。

 

二、虚存

要高性能则需要增加物理内存,而增加物理内存则增加成本。为在成本和性能之间找到一个较好的平衡点,虚存的技术应运而生。

不同的体系结构,其各自的内存结构也存在一定的差异。如:SHX系列和MIPS系列的CPU,起物理地址的映射是由CPU来完成的,内核可以直接访问512MB的物理内存;而对X86和ARM系列的CPU来说,在启动的过程中,内核会将现有的物理地址全部映射到0x8000 0000以上的虚拟地址空间中。

Windows CE与Windows XP的共同点:1、都支持4GB大小的虚拟地址空间,上面的2GB归系统使用,下面的2GB归应用程序使用。2、保留最低的64KB的地址空间,任何进程都不可以访问。

Windows CE与Windows XP的不同点:主要体现在低的2GB空间分配上。Windows CE中每个应用程序的内存空间都是受保护的;从最低的虚拟地址空间开始,系统把这一部分分成了33个槽,每个槽的大小为32MB;0号槽存放的是当前激活的进程,通过微处理的页转换表来实现。

Windows CE采用的是分页式虚拟存储(Page Virtual Memory System),微处理管理的最小内存单元叫做页。当一个应用程序需要访问一个页的时候,微处理器就会根据需要把虚拟地址转换成RAM或ROM中的实际物理地址。根据处理器类型,Windows CE中一个页的大小是1024个字节或者4096个字节。

虚拟内存分为3种状态:1、未使用的(free):未使用的虚拟页面,可以被分配的;2、保留的(reserved):已经被预定了,但还没与实际的物理地址对应,不能被程序使用;3、占用的(committed):已经与实际的物理地址对应了。

Windows CE中,虚拟内存被分成64KB大小的一个个区域,然后在每个区域空间中的页面被按页提交。

有关虚拟内存的一些函数:

1、分配和预订保留虚拟内存

LPVOID VirtualAlloc(LPVOID lpAddress,DWORD dwSize,DWORD flAllocationType,DWORD flProtect)

lpAddress:虚拟地址空间的首地址。若设置为0则内核将自动查找一个符合要求的首地址;

dwSize:为空间的大小;

flAllocationType:分配类型;

flProtect:分配的虚拟地址空间设置保护标志。

2、设置虚拟内存

BOOL VirtualFree(LPVOID lpAddress,DWORD dwSize,DWORD dwFreeType)

lpAddress:虚拟地址空间的首地址;

dwSize:为需要释放的虚拟内存的大小;

dwFreeType:指定的释放类型;

3、更改虚拟内存空间的访问权限

BOOL VirtualProtect(LPVOID lpAddress,DWORD dwSize, DWORD flNewProtect,DWORD lpflOldProtect)

lpAddress:需要重新定义访问权限的虚拟内存的首地址;

dwSize:虚拟内存空间的大小;

flNewProtect:新定义的访问权限;

lpflOldProtect:和参数flNewProtect相对应,lpflOldProtect为原来虚拟地址空间中第一个页面的保护标志。

4、查询一个虚拟地址空间的保护权限

DWORD VirtualQuery(LPVOID lpAddress,PMEMORY_BASIC_INFORMATION lpBuffer, DWORD dwLength)

lpAddress:被查询虚拟地址空间的首地址;

lpBuffer:为指向PMEMORY_BASIC_INFORMATION结构的指针;

dwLength:为PMEMORY_BASIC_INFORMATION结构的大小。

PMEMORY_BASIC_INFORMATION结构定义如下:

Typedef struct _PMEMORY_BASIC_INFORMATION{

PVOID BaseAddress; //查询函VirtualQuery的基地址

PVOID AllocationBase; //用VirtualAlloc函数分配内存时,实际分配的基地址

PVOID AllocationProtect; //分配该页面时页面的一些属性

PVOID RegionSize; //从BaseAddress开始,具有相同属性页面的大小

PVOID State; //页面的状态,有释放,预定,提交三种

PVOID Protect; //当前虚拟地址空间的保护标志

PVOID Type; //内存空间的类型

}PMEMORY_BASIC_INFORMATION

 

三、堆

从本质上说,堆是一段连续的、相对较大的虚拟地址空间。

使用堆以字节单位来申请和释放内存,这种方式的粒度比分页式虚拟存储要小得多,从而提高应用程序的执行效率

Windows CE中只允许在堆中程序申请静态的(不能移动的)内存块,因此,有可能会产生一系列碎片。

在Windows CE中,每个堆都是由一个信号量来控制访问的,两个进程如果想同时访问一个堆是不允许的。

“粒度”:实际上是数据的细化程度,细化程度越高,粒度越小;细化程度越低,粒度越大。如:调用系统的API函数,调用的频率较高则粒度越小。

任意一个程序在启动的时候,都会创建一个本地堆,通过LocalAlloc、LocalFree和LocalRealloc函数可以对本地堆中的内存块进行分配、释放和调整大小。

缺省情况下,Windows CE系统会保留384个页作为本地堆,但是这些页只有在分配的时候才会提交。如果程序需要在本地堆上分配超过188KB的空间,系统就会为本地堆分配多余的空间。

Windows CE中,分配内存、释放内存和重定义内存大小的函数只是Win32中与本地堆相关函数的一个子集。

1、在本地堆中分配内存

HLOCAL LocalAlloc(UINT uFlags,UINT uBytes);

这个函数返回一个指向本地内存块的句柄;参数uFlags描述的是分配内存块的类型;参数uBytes则表示所分配内存块的大小。

2、释放本地堆中的内存块

HLOCAL LocalFree(HLOCAL hMem);

当分配内存块成功的时候,这个函数将返回一个NULL值。

3、重新设置内存块大小

HLOCAL LocalReAlloc(HLOCAL hMem,UINT uBytes,UINT uFlag);

hMem:由LocalAlloc函数返回的一个指针;uBytes:被重新设置的内存块的大小;uFlags:被重新分配的内存块特性。

4、查询内存块大小

UINT LocalSize(HLOCAL hMem);

 

为了避免本地堆中出现的碎片现象,当我们在一段时间里需要一段连续的空间,更好的方式是创建一个独立堆。当文件被打开或者被关闭的时候,这些独立堆将被创建或者释放。

1、创建独立堆

HANDLE HeapCreate(DWORD flOptions,DWORD dwInitialSize,DWORD dwMaximumSize);

flOptions可以为NULL后者HEAP_NO_SERIALIZE;dwInitialSize指定的是开始创建堆时提交的物理内存的大小,设置成0表示初始化设置成提交1个页;dwMaximumSize表示创建的堆的空间的最大值,设置为0则表示让Windows来决定保留多少页。

堆的默认大小是188KB;

Windows CE中的HeapCreate函数只是创建了一个堆,而没有给这个堆分配或者保留任何的内存空间。

2、在独立堆中分配内存

LPVOID HeapAlloc(HANDLE hHeap,DWORD dwFlags,DWORD dwBytes);

这个函数返回的类型是指针,而不是句柄,这跟LocalAlloc函数不大一样;

hHeap为制定堆的句柄;dwFlags为标志,可以为HEAP_NO_SERIALIZE和HEAP_ZERO_MEMORY;dwBytes为指定分配的大小,它是以字节为单位的。

3、在独立堆中释放内存

BOOL HeapFree(HANDLE hHeap,DWORD dwFlags,LPVOID lpMem);

hHeap为指定堆的句柄;dwFlags为标志,只允许为HEAP_NO_SERIALIZE;lpMem为指向被释放内内存块的指针。

4、在独立堆中重新分配内存大小

LPVOID HeapReAlloc(HANDLE hHeap,DWORD dwFlags,LOVOID lpMem,DWORD dwBytes);

参数表示:(句柄;标志;内存块指针;内存块大小)

5、在独立堆中查询堆的大小

DWORD HeapSize(HANDLE hHeap,DWORD dwFlags,LOVOID lpMem);

参数表示:(句柄;标志;内存块指针)

6、释放独立堆

BOOL HeapDestroy(HANDLE hHeap);

 

四、栈

栈也是一段连续的虚拟地址空间,但和堆相比,栈的空间要相对小一些,创建的栈的默认最大值为58KB;

栈是专门为函数使用而设计的;

在程序设计时,要尽量避免分配很多、很大的内存块,这样在发现没有足够可用的物理RAM时,线程挂起,一个给定时间无响应后出现系统异常。最好是在堆中分配大的内存块,并且一定要在使用以后把堆释放掉,或者也可以通过在创建线程时指定栈的大小来避免这个问题。

 

五、静态数据块

Windows CE中的静态数据块是一个程序启动时候加载的内存块。这些内存块包含了字符集、缓冲区和程序需要的静态数据。

Windows CE中,系统会为每一个应用程序申请2个RAM块,一个存放读/写数据,一个存放只读数据。

如:我们在编写一个基于ROM的程序的时候,尽量把数据放在只读静态数据区中。

你可能感兴趣的:(windows,api,XP,null,basic,存储)