在应用程序中使用虚拟内存
在Windows中可以使用3中机制进行对内存操控
1、虚拟内存 适合用来管理大型对象数组或大型结构数组
2、内存映射文件 管理大型数据流,通常是文件,以及在同一机器上运行的多个进程之间共享数据
3、堆 管理大量的小型对象
1、预订地址空间区域
要访问在内存中地址,必须先进行地址空间区域的预订,这步就是告诉系统要预订地址空间中的哪一块。这是在进程的地址空间中,这其实还是在虚拟地址空间中。我们必须使用VirtualAlloc函数,函数执行之后,它会预订一块区域并返回该区域的基地址。系统会根据CPU页面的大小的整数倍来预订区域的。
2、给区域调拨物理存储器
系统必须从页交换文件中调拨物理存储器给区域,在调拨物理存储器时,起始地址始终是页面大小的整数倍,而整个大小也是页面大小的整数倍。我们依旧使用的是上面的函数。不过是在第二个参数使用的是MEM_COMMIT,而作为预订的则是MEM_RESEVER。这里要注意的是保护属性,也就是页面的保护属性,在整个页面中是一样的,但是在不同的页面是可以不一样的。
当然我们可以同时进行预订和分配物理存储器。
Windows还提供了大页面支持。这样在处理大块内存的时候可以提升性能。但是这是以它只能放在内存中,是不能进行页面交换为代价的。这就需要在内存中锁定页面。而且必须室友一定的权限。
3、若现在我们在处理着表格数据,因为表格中数据是有一定的规律的,于是这就有点类似数组,但是建立多维数组,以多大为好呢?因为我们不知道要使用多少的内存,于是势必会申请很多,会浪费很多的内存,那么使用链表,但是要是对某个单元格进行更改,这中过程就显得效率很低。于是我们使用虚拟技术进行操作。
1)预订一块足够大的内存给这个结构,这种过程不会消耗物理存储器。
2)当用户在单元格中输入数据,先确定这个结构在区域中的内存地址,然后进行访问,若访问失败,引发异常,那么再进行物理存储器的调拨。
3、撤销调拨物理存储器及释放区域
使用VirtualFree进行物理存储器的撤销或是释放地址空间中的一整块区域。我们不能只释放一部分的空间,必须释放申请时候返回来的地址基址中指明的区域空间大小。若给定的内存地址在页面的中间,记住,分配粒度的大小与页面大小是不一样的。这样的话就会撤销整个页面。当我们对dwSize传递值为0的时候,会将调拨给这个区域的所有页面都撤销。
4、何时进行撤销调拨物理存储器。
我们可以创建一个数组,数组中保存的是Bool类型值,它的大小与CPU平台页面的大小是一样的。将结构放到已经调拨的内存中就将bInUse设置为True。
程序运行中,会使用的优先级的线程来观测所有结构的bIsUser的属性。若结构中所有这一位都为false,就使用垃圾收集函数。
5、重置物理存储器内容
有些应用程序不需要保留存储器中的内容,于是我们就不需要在页交换文件中保存指定的存储页,因此若系统决定将内存页作为其它的使用,则页面的内容将不会被保存到交换文件中,也就是说这个页面中数据将会被替换掉。
这就是重置物理存储器,相当于告诉系统一个或几个物理存储页中的数据没有被修改过。因为若系统在查找一页内置内存,找到了一个修改过的页面,那么系统就一定会将这个页面写入到页交换文件中,这个操作的速度比较的慢,会严重的影响性能。
如何做到让系统认为这块页面是没有经过修改的呢?在调用VirtualAlloc函数中,在第三个参数中传MEM_RESRT标志。 当对页面进行重置之后,页面中的内容将是垃圾。在进行重置中,会将大小置为页面大小的整数倍,并向下去整,因为如果垃圾并没有占满整个内存页的话,我们并不希望重置整个页面。因为其中很可能还有有效数据。所以但凡是小于页面大小的,都会报错。因为取整回到0.但是重置0个字节是没有意义的。而且MEM_RESE只能是单独使用,不能将它和其它的标志位或起来。而且这种组合起来是没有意义的。
6、地址窗口拓展
为什么会有地址窗口拓展,提高性能,服务器应用程序需要在内存中保存更多的数据以减少磁盘和内存间的页交换。AWE提供让应用程序分配一块或多块内存,程序预订地址空间区域,VirtualAlloc函数。然后使用的是AllocateUserPhysicalPages进行分配物理存储器。在这个函数中会指定进程,以及分配的页面的大小,以及页面的页框号,页框号就是在系统分配内存页面时,将内存页面的页框号保存到aRAWPages参数所指向的数组中,然后再通过MapUserPhysicalPages将内存快指定给地址窗口。函数中的第一个参数是窗口的虚拟地址,后面的参数同样是页的大小以及指向页框的数组的指针。这种方式又是大页面以及重置页面后的又一个提升性能的方法。
在撤销的时候使用FreeUserPhysicalPages,将调用的内存块释放它。而且必须使用FreeVirtual函数进行清理。