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_NOACCESSPAGE_READWRITEPAGE_READONLYPAGE_EXECUTEPAGE_EXECUTE_READPAGE_EXECUTE _READWRITE。但是,既不能设定PAGE_WRITECOPY属性,也不能设定PAGE_EXECUTE_WRITECOPY属性。如果设定了这些属性,VirtualAlloc函数将不保留该区域,并且返回NULL。另外,当保留地址空间区域时,不能使用保护属性标志PAGE_GUARDPAGE_NOCACHEPAGE_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范围内的所有页面均被回收。