Windows CE分配大容量内存
源码下载:http://download.csdn.net/source/875041
1.背景
最近,我在把PC上的扫描仪驱动源码移植到Window CE系统中,遇到了内存分配的问题。我在CE进程中,要一次性分配高达 40M 的内存大小时就提示失败,说内存不足,可是内存是 512M 的肯定足够。本来对内存分配不甚了解,苦苦折腾,总算解决。再此做个Windows CE的内存分配的总结。一来是我温故知新,二来供他人参考之用。
2. WCE内存简介
在进入主题之前,我想有必要简要了解下WCE的内存(详细了解可以参看有关书籍)。
2.1、WCE内存结构
Windows CE是一个保护模式的操作系统,每个进程的地址空间都是相对独立的,因此程序的访问只能使用虚拟内存。Windows CE对整个系统实现了一个线性的32位(232,即4GB)的虚拟地址空间。
Windows CE.net只能管理512MB的物理内存和4GB大小的虚拟地址空间。这4GB的虚拟地址空间被分为2个的2GB的区域,一个是2GB的内核空间(程序无法访问,以保证系统的安全),一个是2GB的用户空间。用户空间又被划分为64个32MB的槽,Windows CE系统最多同时可以运行32个进程,每个进程都有它自己受保护的、32MB的地址空间(而Windows XP拥有2GB的私有地址空间),同时也受到了32MB空间大小的限制。
2.2、堆和栈
堆是一段连续的相对较大的虚拟地址空间。堆具有以下特点:
◆堆是向高地址扩展的数据结构
◆一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。在堆中分别内存是以字节为单位。如malloc、new等。
◆默认堆
当运用程序启动时,内核在进程地址所在空间中为进程分配了一个192K大小的虚拟地址空间作为默认堆使用。但是并不立刻提交物理内存。如果在运行当中192KB不能满足需求,那么内核会在进程地址空间中重新查找一个足够大小的空闲的地址空间,然后复制原来堆的数据,最后释放原来的堆所占的地址空间。这是因为默认的堆的高地址处还有栈,所以必须重新分配一个。
◆优点
堆的优点是能在一定范围内减少内存碎片。
◆缺点
Windows CE.NET的堆有明显的缺点,不同于其它Windows操作系统下的堆管理,在Windows CE.NET的堆中创建的内存块不能够移动,多次创建内存块、释放内存块会产生内存碎块,这样的话当需要分配一个大一点的连续的内存块时,本来空闲的内存块加起来足够用,但是这些内存块是分隔的,不符合要求。像Windows 2000或98的内核会频繁的移动分散的正使用的内存块,使它们聚集在一起。这也是为什么有时需要句柄而不用指针的原因。由于Windows CE.NET的堆的缺点,开发者如果要频繁的在堆中创建、释放内存块的话,最好自己创建一个单独的堆,而不用默认的堆。
栈具有如下特点:
◆栈是向低地址扩展的数据结构
◆栈由编译器自动分配释放 ,如一个函数的参数和局部变量都在栈上。
◆栈也是一段连续的虚拟地址空间,和堆相比空间要小的多,它是专为函数使用的。
◆修改栈大小
可以在编译器设置修改栈的大小,或者在创建线程时指定栈的大小。如果采用在编译链接时修改大小,那么所有栈的大小都会改变。
2.4 内存映射文件
内存映射文件能保留一个虚拟地址空间,并提交物理内存。内存映射文件常用于:
◆映射大容量文件
运用程序不必在访问文件之前申请很大的内存作为读取文件的缓存区。
◆进程间通信
也是进程通信间的主要手段,其他进程间的通信机制都是基于内存映射文件来完成的。
◆申请大容量的虚拟地址空间
内存映射文件在全局地址空间内(0x420000到0x7FFFFFFF)分配。
2.5 申请效率的比较:
◆堆是由malloc、new等分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。
◆栈由系统自动分配,速度较快。但程序员是无法控制的。
◆在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。
3、比较分配内存的各种方法
看看这里:http://msdn.microsoft.com/en-us/library/aa366533(VS.85).aspx
Comparing Memory Allocation Methods
The following is a brief comparison of the various memory allocation methods:
- CoTaskMemAlloc
- GlobalAlloc
- HeapAlloc
- LocalAlloc
- malloc
- new
- VirtualAlloc
Although the GlobalAlloc, LocalAlloc, and HeapAlloc functions ultimately allocate memory from the same heap, each provides a slightly different set of functionality. For example, HeapAlloc can be instructed to raise an exception if memory could not be allocated, a capability not available with LocalAlloc. LocalAlloc supports allocation of handles which permit the underlying memory to be moved by a reallocation without changing the handle value, a capability not available with HeapAlloc.
Starting with 32-bit Windows, GlobalAlloc and LocalAlloc are implemented as wrapper functions that call HeapAlloc using a handle to the process's default heap. Therefore, GlobalAlloc and LocalAlloc have greater overhead than HeapAlloc.
Because the different heap allocators provide distinctive functionality by using different mechanisms, you must free memory with the correct function. For example, memory allocated with HeapAlloc must be freed with HeapFree and not LocalFree or GlobalFree. Memory allocated with GlobalAlloc or LocalAlloc must be queried, validated, and released with the corresponding global or local function.
The VirtualAlloc function allows you to specify additional options for memory allocation. However, its allocations use a page granularity, so using VirtualAlloc can result in higher memory usage.
The malloc function has the disadvantage of being run-time dependent. The new operator has the disadvantage of being compiler dependent and language dependent.
The CoTaskMemAlloc function has the advantage of working well in either C, C++, or Visual Basic. It is also the only way to share memory in a COM-based application, since MIDL uses CoTaskMemAlloc and CoTaskMemFree to marshal memory.
4、WCE中申请大容量内存
WCE运用程序的地址空间局限于32MB所引起的另外一个问题是如何分配大类型内存块。那么如何才能突破 32M 限制呢?
看看我的测试程序,用了不同的分配内存的方法来分配最大的内存。点击“Alocates Memory”开始分配,如图4-1可以看出,除了用内存映射外,其他的都无法突破 32M ,哪怕VirtualAlloc也不行。如果多次“Alocates Memory”你会发现内存映射文件能分配到的内内存越来越小,这我还没搞明白是什么原因,可能是内存碎片引起的。
图4-1 WCE中各种方法分配最大内存
5、总结
写了好久,感觉写得好乱……^_^。但不管了,先发表,以后慢慢修改。如有错误,恳请赐教!