Windows提供了3种进行内存管理的方法:
• 虚拟内存,最适合用来管理大型对象或结构数组。
• 内存映射文件,最适合用来管理大型数据流(通常来自文件)以及在单个计算机上运行的多个进程之间共享数据。
• 内存堆栈,最适合用来管理大量的小对象。
虚拟内存
在地址空间中保留一个区域
通过调用VirtualAlloc函数,可以在进程的地址空间中保留一个区域:
PVOID VirtualAlloc(
PVOID pvAddress,
SIZE_T dwSize,
DWORD fdwAllocationType,
DWORD fdwProtect);
第一个参数pvAddress包含一个内存地址,用于设定想让系统将地址空间保留在什么地方。
如果在特定的地址上不存在空闲区域,或者如果空闲区域不够大,那么系统就不能满足你的要求,VirtualAlloc函数返回NULL。注意,为pvAddress参数传递的任何地址必须始终位于进程的用户方式分区中,否则对VirtualAlloc函数的调用就会失败。
地址空间区域总是按照分配粒度的边界来保留的(迄今为止在所有的Windows环境下均是64KB)。
第二个参数是dwSize,用于设定想保留的区域的大小(以字节为计量单位)。由于系统保留的区域始终必须是CPU页面大小的倍数。
第三个参数是fdwAllocationType,它能够告诉系统你想保留一个区域还是提交物理存储器(这样的区分是必要的,因为VirtualAlloc函数也可以用来提交物理存储器)。若要保留一个地址空间区域,必须传递MEM_RESERVE标识符作为FdwAllocationType参数的值。
如果保留的区域预计在很长时间内不会被释放,那么可以在尽可能高的内存地址上保留该区域。这样,该区域就不会从进程地址空间的中间位置上进行保留。因为在这个位置上它可能导致区域分成碎片。如果想让系统在最高内存地址上保留一个区域,必须为pvAddress参数fdwAllocationType 参数传递NULL,还必须逐位使用OR 将MEM_TOP_DOWN标志和MEM_RESERVE标志连接起来
最后一个参数是fdwProtect,用于指明应该赋予该地址空间区域的保护属性。与该区域相关联的保护属性对映射到该区域的已提交内存没有影响。
当保留一个区域时,应该为该区域赋予一个已提交内存最常用的保护属性。例如,如果打算提交的物理存储器的保护属性是PAGE_READWRITE(这是最常用的保护属性),那么应该用PAGE_READWRITE保护属性来保留该区域。当区域的保护属性与已提交内存的保护属性相匹配时,系统保存的内部记录的运行效率最高。
可以使用下列保护属性中的任何一个: PAGE_NOACCESS、PAGE_READWRITE、PAGE_READONLY、PAGE_EXECUTE、PAGE_EXECUTE_READ或PAGE_EXECUTE _READWRITE。但是,既不能设定PAGE_WRITECOPY属性,也不能设定PAGE_EXECUTE_WRITECOPY属性。如果设定了这些属性,VirtualAlloc函数将不保留该区域,并且返回NULL。另外,当保留地址空间区域时,不能使用保护属性标志PAGE_GUARD,PAGE_NOCACHE或PAGE_WRITECOMBINE,这些标志只能用于已提交的内存。
在保留区域中的提交存储器
当保留一个区域后,必须将物理存储器提交给该区域,然后才能访问该区域中包含的内存地址。物理存储器总是按页面边界和页面大小的块来提交的。
若要提交物理存储器,必须再次调用VirtualAlloc函数, fdwAllocationType参数传递的是MEM_COMMIT, 不必立即将物理存储器提交给整个区域(可以先提供一部分)。
同一个内存页面的不同部分不能使用不同的保护属性。然而,区域中的一个页面可以使用一种保护属性(比如PAGE_READWRITE),而同一个区域中的另一个页面可以使用不同的保护属性(比如PAGE_READONLY)。
同时进行区域的保留和内存的提交
PVOID pvMem = VirtualAlloc(NULL, 99 * 1024,
MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
回收虚拟内存和释放地址空间区域
BOOL VirtualFree(
LPVOID pvAddress,
SIZE_T dwSize,
DWORD fdwFreeType);
参数pvAddress:必须是该区域的基地址。此地址与该区域被保留时VirtualAlloc函数返回的地址相同。
参数dwSize:系统知道在特定内存地址上的该区域的大小,因此可以为dwSize参数传递0。实际上,必须为dwSize参数传递0,否则对VirtualFree的调用就会失败。
参数fdwFreeType:必须传递MEM_RELEASE,以告诉系统将所有映射的物理存储器提交给该区域并释放该区域。
当释放一个区域时,必须释放该区域保留的所有地址空间。例如不能保留一个128 KB的区域,然后决定只释放它的64 KB。必须释放所有的128 KB。
当想要从一个区域回收某些物理存储器,但是却不释放该区域时,也可以调用VirtualFree函数。
若要回收某些物理存储器,必须在VirtualFree函数的pvAddress参数中传递用于标识要回收的第一个页面的内存地址,还必须在dwSize参数中设定要释放的字节数,并在fdwFreeType参数中传递MEM_DECOMMIT标志。
与提交物理存储器的情况一样,回收时也必须按照页面的分配粒度来进行。这就是说,设定页面中间的一个内存地址就可以回收整个页面。当然,如果pvAddress + dwSize的值位于一个页面的中间,那么包含该地址的整个页面将被回收。因此位于pvAddress 至pvAddress +dwSize范围内的所有页面均被回收。
本文地址:http://www.cnblogs.com/fangyukuan/archive/2010/09/06/1818724.html