Windows提供了以下三种机制对内存进行操控:

  一:虚拟内存。适合来管理大型对象数据或大型结构数组。

  二:内存映射文件。适合用来管理大型数据流,以及在同一机 器上运行的多个进程之间共享数据。

  三:堆。适合用来管理大量的小型对象。

  很多人都对VirtualAlloc和malloc 或new的区别不是很清楚,我也一样。搜索下了,发现这句话说的很清楚了:

  VirtualAlloc要进入内核模式,算法特复杂,比较慢,而且分配粒度是4k,用来分配小块内存很浪费

  malloc先用VirtualAlloc弄一大块内存,后面在堆上分配时不用进入内核模式,算法也简单些,而且分配粒度比较小

  VirtualAlloc只能分配4KB为单位的页面,适合大型数据或者内存映射文件等用途。而堆的申请分配没有这个限制,更为灵活。

  有的人嫌malloc还不够精简,于是又在堆上面开辟自己的内存池,更加轻量级

  本文将主要介绍虚拟内存。

  Windows提供了一些用来操纵虚拟内存 的函数,我们可以通过这些函数直接预订地址空间区域,并给这些预订的区域调拨来自页交换文件的物理存储器。

  预定地址空间区域。

  可以通过调用VirtualAlloc函数来运行:


PVOID VirtualAlloc(

      PVOID pvAddress,

      SIZE_T dwSize,

      DWORD fdwAllocationType,

      DWORD fdwProtect);
 


  pvAddress是内存地址。用来告诉我们想要运行地址空间中的哪一块。

  当传入NULL时,系统会自动找到一块闲置区域。

  如果在pvAddress标识的内存块中找不到闲置区域,或闲置区域不够大函数将返回NULL。

  如果VirtualAlloc能满足我们的要求,它会预定一块区域并返回该区域的基地址。

  dwSize用来指定我们想要预订的区域大小。以字节为单位。 系统始终以cpu页面大小整数倍来预定区域。且起始地址是按照分配粒度64kB的整数倍来预定的。

  fdwAllocationType用来告诉系统我们到底是要预订还是要调拨物理存储器。如果要预订区域可以传入:MEM_RESERVE。如果我们想让系统从尽可能高的内存地址来预定区域,必须传入NULL给pvAddress,同时对MEM_TOP_DOWN和MEM_RESERVE标志进行按位或操作。

  fdwProtect给区域指定保护属性。区域的保护属性对调拨给该区域的物理存储器不起任何作用。无论指定何种保护属性,只要还未给该区域调拨物理存储器都会导致访问违规。

  预订时指定的属性应该跟调拨时指定的属性相同,这样系统内部处理效率会更高。

  调拨物理存储器

  预定区域后还需要给该区域调拨物理存储器。系统会从页交换文件中调拨物理存储器给该区域。在调拨物理存储器时,起始地址和区域大小始终都是页面大小的整数倍。调拨物理存储器同样需要调用VirtualAlloc。但这次我们需要传入MEM_COMMIT来作为fdwAllocationType的值。

  pvAddress标识要调拨物理存储器的区域的起始地址。

  dwSize表示物理存储器的大小。以字节为单位。我们并不需要给整个区域都调拨物理存储器。

  有了起始地址和大小可以标识一段区域。

  同时预定和调拨物理存储器

  有时我们项同时预定区域并给该区域调拨物理存储器。同样需要调用VirtualAlloc。但是MEM_RESERVE要和MEM_COMMIT按位或并将它们传给fdwAllocationType。此时系统会为整个区域调拨物理存储器。