=============================================================
标题:Windows CE虚拟内存
备注:
日期:2011.3.12
姓名:朱铭雷
=============================================================
一 获取系统内存信息:
MEMORYSTATUS memstatus;
memstatus.dwLength = sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&memstatus);
结果:
dwMemoryLoad字段表示当前内存使用率为34%,但这个数字不精确。
dwTotalPhys字段表示当前的程序内存总计为52104KB(53354496个byte)。
dwAvailPhys字段表示当前可用的程序内存还剩34736(KB)(35569664个byte)。
dwTotalVirtual字段表示当前程序可以使用的虚拟地址空间总量为32M,可用的还剩27.8M。
我测试的系统是Windows CE 5.0,系统中最多可以有32个进程,每个进程可以使用的虚拟地址空间为32M。这种情况在Windows CE 6.0中得到了很大改善,最大进程数貌似是32K个,每个进程可以使用的虚拟地址空间为2G。
Windows CE 5.0的进程虚拟地址空间分配图:
Windows CE 6.0的进程虚拟地址空间分配图:
二 虚拟内存
1 VirtualAlloc 分配虚拟内存
const int PAGESIZE = 4096;
LPVOID pMem1 = 0, pMem2 = 0;
pMem1 = VirtualAlloc(NULL, PAGESIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
pMem2 = VirtualAlloc(NULL, PAGESIZE, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
这段代码的本意是想分配两个单页(4K字节)大小的虚拟内存,第一个参数设置为NULL,由系统来决定在何处分配内存。访问权限是可读可写。
但实际调试时发现,每次提交一个页面大小的虚拟内存时,实际上分配的是0x10000(64K字节)大小的虚拟内存,原因是进行了64KB字节的边界对齐,这就造成了虚拟内存空间的严重浪费。理想一点的解决方法是,首先“保留”(MEM_RESERVE)一块64KB(或其整数倍)字节大小的虚拟内存,然后在需要的时候提交该区域的一个页面或几个页面。
const int PAGESIZE = 4096;
LPVOID pMemBase = 0, pMem1 = 0, pMem2 = 0;
pMemBase = VirtualAlloc(NULL, PAGESIZE*16, MEM_RESERVE, PAGE_NOACCESS);
pMem1 = VirtualAlloc(pMemBase, PAGESIZE, MEM_COMMIT, PAGE_READWRITE);
pMem2 = VirtualAlloc((PBYTE)pMemBase+PAGESIZE, PAGESIZE, MEM_COMMIT, PAGE_READWRITE);
调试时,可以看出pMem1所指的虚拟内存,实际分配了0x1000(4K字节)大小的虚拟内存。
2 VirtualFree回收释放虚拟内存
回收是使页面处于“保留”状态,取消虚拟内存到物理内存之间的映射。上面那段代码申请了64KB大小的虚拟内存,其中8KB(两页)处于“提交”状态,剩余处于“保留”状态。这时先回收已“提交”部分,再整体“释放”。如果区域中既有“提交”页面,又有“保留”页面,则VirtualFree将失败。
VirtualFree(pMem1, PAGESIZE, MEM_DECOMMIT);
VirtualFree(pMem2, PAGESIZE, MEM_DECOMMIT);
VirtualFree(pMemBase, 0, MEM_RELEASE);
3 VirtualProtect改变访问权限
VirtualProtect只能改变已“提交”页面的访问权限。
DWORD dwOldProtect = 0;
VirtualProtect(pMem1, PAGESIZE, PAGE_READONLY, &dwOldProtect);
4 VirtualQuery查询访问权限
MEMORY_BASIC_INFORMATION memInfo;
VirtualQuery(pMemBase, &memInfo, sizeof(MEMORY_BASIC_INFORMATION));
BaseAddress是传递给VirtualQuery函数准备查询权限的页地址,AllocationBase是VirtualAlloc分配虚拟内存时的初始地址,AllocationProtect为1(PAGE_NOACCESS),说明该区域最初分配时访问权限为PAGE_NOACCESS,RegionSize包含从BaseAddress地址开始,具有相同属性的页的字节大小,这里为0x1000(4KB)字节大小,实际上就是pMem1所指的区域大小,其属性PAGE_READONLY(经过上面更改)与pMem2所指的区域PAGE_READWRITE不同。State为0x1000(MEM_COMMIT)表明该区域中的页面处于“提交”状态。Protect为0x02(PAGE_READONLY),是该区域当前的访问权限。Type为0x20000(MEM_PRIVATE),表明该区域为当前进程私有。