Wi n d o w s提供了3种进行内存管理的方法,它们是:
• 虚拟内存,最适合用来管理大型对象或结构数组。
• 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据。
• 内存堆栈,最适合用来管理大量的小对象。
用于管理虚拟内存的函数可以用来直接保留一个地址空间区域,将物理存储器(来自页文件)提交给该区域,并且可以设置你自己的保护属性。
1.在地址空间中保留一个区域
PVOID VirtualAlloc(
PVOID pvAddress,
SIZE_T dwSize,
DWORD fdwAllocationType,
DWORD fdwProtect);
第一个参数p v A d d r e s s包含一个内存地址,用于设定想让系统将地址空间保留在什么地方。在大多数情况下,你为该参数传递M U L L。它告诉Vi r t u a l A l l o c,保存着一个空闲地址区域的记录的系统应该将区域保留在它认为合适的任何地方。
第二个参数是d w S i z e,用于设定想保留的区域的大小(以字节为计量单位)。由于系统保留的区域始终必须是C P U页面大小的倍数,因此,如果试图保留一个跨越6 2 K B的区域,结果就会在使用4 KB、8 KB或16 KB页面的计算机上产生一个跨越6 4 K B的区域。
第三个参数是f d w A l l o c a t i o n Ty p e,它能够告诉系统你想保留一个区域还是提交物理存储器(这样的区分是必要的,因为Vi r t u a l A l l o c函数也可以用来提交物理存储器)。若要保留一个地址空间区域,必须传递M E M _ R E S E RV E标识符作为F d w A l l o c a t i o n Ty p e参数的值。
最后一个参数是f d w P r o t e c t,用于指明应该赋予该地址空间区域的保护属性。与该区域相关联的保护属性对映射到该区域的已提交内存没有影响。无论赋予区域的保护属性是什么,如果没有提交任何物理存储器,那么访问该范围中的内存地址的任何企图都将导致该线程引发一个访问违规。
2.在保留区域中的提交存储器
当保留一个区域后,必须将物理存储器提交给该区域,然后才能访问该区域中包含的内存地址。系统从它的页文件中将已提交的物理存储器分配给一个区域。物理存储器总是按页面边界和页面大小的块来提交的。
若要提交物理存储器,必须再次调用Vi r t u a l A l l o c函数。不过这次为f d w A l l o c a t i o n Ty p e参数传递的是M E M _ C O M M I T标志,而不是M E M _ R E S E RV E标志。传递的页面保护属性通常与调用Vi r t u a l A l l o c来保留区域时使用的保护属性相同(大多数情况下是PA G E _ R E A D W R I T E),不过也可以设定一个不同的保护属性。
在已保留的区域中,你必须告诉Vi r t u a l A l l o c函数,你想将物理存储器提交到何处,以及要提交多少物理存储器。为了做到这一点,可以在p v A d d r e s s参数中设定你需要的内存地址,并在d w S i z e参数中设定物理存储器的数量(以字节为计量单位)。注意,不必立即将物理存储器提交给整个区域。
3.同时进行区域的保留和内存的提交
有时你可能想要在保留区域的同时,将物理存储器提交给它。只需要一次调用Vi r t u a l A l l o c函数就能进行这样的操作,如下所示:
PVOID pvMem = VirtualAlloc(NULL, 99 * 1024,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
4.回收虚拟内存和释放地址空间区域
BOOL VirtualFree(
LPVOID pvAddress,
SIZE_T dwSize,
DWORD fdwFreeType);
5.改变保护属性
虽然实践中很少这样做,但是可以改变已经提交的物理存储器的一个或多个页面的保护属性。例如,你编写了一个用于管理链接表的代码,将它的节点存放在一个保留区域中。可以设计一些函数,以便处理该链接表,这样,它们就可以在每个函数开始运行时将已提交内存的保护属性改为PA G E _ R E A D W R I T E ,然后在每个函数终止运行时将保护属性重新改为PA G E _ N O A C C E S S。
通过这样的设置,就能够使链接表数据不受隐藏在程序中的其他错误的影响。如果进程中的任何其他代码存在一个迷失指针,试图访问你的链接表数据,那么就会引发访问违规。当试图寻找应用程序中难以发现的错误时,利用保护属性是极其有用的。
若要改变内存页面的保护属性,可以调用Vi r t u a l P r o t e c t函数:
BOOL VirtualProtect(
PVOID pvAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD pflOldProtect);