这段代码首先调拨了一块存储器,然后将这块内存的前4个字节标记为可以被重置。但是重置存储器的操作会调用失败。第二个VirtualAlloc会返回NULL。GetLastError会返回ERROR_INVALID_ADDRESS。
这是因为在传入MEM_RESET给VirtualAlloc时,函数会把基地址向下取整到页面大小的整数倍。(其他标志时都是向上去整,此处要注意。)其目的是确保在同一页面中还有其他重要数据的情况下,不会把它们丢弃。前面的例子,向下去整到页面整数倍是0,这是没有意义的。也就是说我们重置的页面必须是一个或几个完整的页面。不足一页的为了保护数据就不将它们设为可重置。
还要注意MEM_RESET不能和其他标志一起使用,它不合群,只能单独使用。否则调用会失败。
VirtualQuery函数。
VirtualQuery可以用来查询与地址空间有关的特定信息。比如大小,存储器类型及保护属性。
DWORD VirtualQuery( LPCVOID pvAddress, PMEMORY_BASIC_INFORMATION pmbi, DWORD dwLength); |
pvAddress指定需要查询的虚拟内存地址。
dwLength指定MEMORY_BASIC_INFORMATION结构大小。
pmbi返回MEM_BASIC_INFORMATION结构地址。该地址定义如下:
typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress;//等于pvAddress向下取整到页面大小。 PVOID AllocationBase;//区域基地址。 DWORD AllocationProtect;//预定区域时的保护属性。 SIZE_T RegionSize;//区域大小。以字节为单位。以BaseAddress为起始地址。 DWORD State;//区域页面的状态。 DWORD Protect;//保护属性 DWORD Type;// }MEMORY_BASIC_INFORMATION,*PMEMORY_BASIC_INFROMATION; |
VirtualQueryEx与VirtualQuery的区别就是它可以传入一个进程句柄。也就意味着它可以查询其他进程地址空间的信息。
GlobalMemoryStatus可以用来取得当前内存状态的动态信息:
VOID GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer); |
MEMORYSTATUS结构定义如下:
typedef struct _MEMORYSTATUS { DWORD dwLenght;//此结构大小。调用函数前必须初始化。 DWORD dwMemoryLoad;// SIZE_T dwTotalPhys; SIZE_T dwAvailablePhys; SIZE_T dwTotalPageFile; SIZE_T dwAvailablePageFile; SIZE_T dwTotalVirtual; SIZE_T dwAvailVirtual; }MEMORYSTATUS,*LPMEMORYSTATUS; |
dwMemoryLoad成员告诉我们内存管理系统有多忙,它可以是0-100之间的任何值。实际中,这个值没有什么用处。
dwTotalPhys成员表示物理内存总量。
dwAvailPhys成员表示可分配的内存总理。都是以字节为单位。
dwTotalPageFile表示硬盘页交换文件最多能存放多少字节的数据。
dwTotalVirtual表示地址空间中各进程私有的那部分字节数。比2G少128k.从0x00000000-0x0000FFFF(空指针赋值分区)和从0x7FFF0000-0x7FFFFFFF(64KB进入分区)这两个分区应用程序不能访问。
dwAvailVirtual是唯一一个与进程有关的成员。它表示还有多少闲置的地址空间可以被使用。也就说dwTotalVirtual-进程预定的地址空间就等于dwAvailVirtual。