第十五章:在应用程序中使用虚拟内存

来源:互联网 发布:php erp系统下载 编辑:程序博客网 时间:2024/05/30 22:43

1:预订

LPVOID VirtualAlloc(LPVOID lpAddress,//可为NULL,也可以指定一个地址,系统会自动向下取整到64KB整数倍SIZE_T dwSize,//系统自动向上取整到页面大小整数倍DWORD flAllocationType,//MEM_RESERVE,还可以传递MEM_TOP_DOWN表示优先从地址空间上方分配内存DWORD flProtect//页面属性,如果和物理存储器页面属性不同,则以物理存储器页面属性为准,//二者相同时性能最高,不能为预订的页面指定写时拷贝属性和PAGE_GUARD属性);

2:调拨
flAllocationType为MEM_COMMIT,调拨的大小向上取整到页面大小整数倍

3:同时预订和调拨

VirtualAlloc(NULL,8000,MEM_RESERVE|MEM_COMMIT,PAGE_READWRITE);

4:大页面支持

1:大页面支持不采用GetSystemInfo()返回的页面大小而采用

SIZE_T GetLargePageMinMum();

返回的大小来分配内存,如果CPU不支持,则此函数返回0,并且必须满足下面几个条件

(1):分配大小dwSize必须是大页面页面大小整数倍

(2):必须同时预订和调拨,也就是MEM_RESERVE|MEM_COMMIT|MEM_LARGE_PAGE

(3):页面属性必须是PAGE_READWRITE

2:大页面分配的内存是不可换页的,也就是能够常驻内存,这就要求调用VirtualAlloc()的用户必须具有锁定页面的用户权限

5:一个大数组的例子

具体见书上,值得说明的是:

(1):当为一块已经调拨物理存储器的页面调拨物理存储器时,VirtualAlloc()会失败

(2):使用SEH,我们在程序设置一个异常,当向未调拨物理存储器的区域写数据时,会产生一个异常,我们捕获此异常,并为其调拨物理存储器,然后告诉系统重新执行刚才的命令

6:释放

1:释放已预订的区域并撤销所有该区域的物理存储器

释放已预订区域的操作必须将整个区域完全释放,而不能只是释放其中的一部分

BOOL VirtualFree(LPVOID lpAddress,//VirtualAlloc()返回的地址SIZE_T dwSize,//释放区域必须传递0DWORD dwFreeType//MEM_RELEASE);

2:撤销调拨给区域的一部分物理存储器,但不释放区域

BOOL VirtualFree(LPVOID lpAddress,//想要撤销物理存储器的第一个页面的地址,会向下取整到页面大小整数倍地址SIZE_T dwSize,//如果为0,则撤销所有页面的物理存储器,会向上取整到页面大小整数倍DWORD dwFreeType//MEM_DECOMMIT);

7:大数组的例子的释放问题
详情见书上,有几种方法:

(1):将数据结构设计的恰好是页面大小,但这太脑残了

(2):使用一个位图同步使用情况,在删除一块数据的同时检查位图,如果发现一个页面的位图都未使用,便可以释放它

(3):基于一个事实:系统在第一次调拨物理存储器时,会将页面清0,详情见书上,我没看懂

8:改变页面属性

BOOL VirtualProtect(LPVOID lpAddress,SIZE_T dwSize,DWORD flNewProtect,//不能是写时复制PDWORD lpflOldProtect//返回之前的页面属性,不能为NULL);

当跨越了不同区域时,此函数不能改变他们的页面属性,这个时候,必须多次调用VirtualProtect()以达到此效果

9:重置物理存储器

1:定义:操作系统在物理内存中分配一块内存时,如果找不到闲置页面,会将一个未修改的页面释放或者将一个已修改的页面换入页交换文件再将其释放,我们分配的内存同样可能被唤出到页交换文件,在下次使用时又被换入物理内存,如果我们并不关系这块数据,这样的操作就很多余,这时,我们就可以重置物理存储器,它会告诉操作系统,如果需要这块内存,当它没有被修改过,直接释放就可以了,当我们下次使用这块页面时,如果系统使用过,它会给我们一个全新的清零的页面,如果系统没有使用过,仍然会返回原来的页面,由于我们不知道系统是否使用过,所以一旦重置了物理存储器,我们应该认为其中的数据都是垃圾

2:为了安全,重置物理存储器,地址会向上取整到页面大小整数倍,大小会向下取整到页面大小整数倍,这和分配释放这些操作取整方式是相反的

3:使用方式是:

VirtualAlloc(8000,1024,MEM_RESET,PAGE_READWRITE);//MEM_RESET只能单独使用,页面属性是没有意义的,但仍然必须传递一个

10:地址窗口扩展(AWE)

1:AWE允许程序以一种特殊方式分配内存,系统保证不会把此内存唤出到磁盘

2:使用AWE的过程是:调用VirtualAlloc()预订一块区域,这块区域叫做地址窗口,调用API分配不会被唤出的内存,将这块内存映射到地址窗口

//地址窗口大小ULONG_PTR ulWindowSize=1024*1024;//预订ulWindowSize大小的地址窗口,MEM_PHYSICAL表示该区域会以物理内存作为后备//地址窗口页面属性必须是PAGE_READWRITE,并且不能通过VirtualProtect()改变其属性PVOID pWindow=VirtualAlloc(NULL,ulWindowSize,MEM_RESERVE|MEM_PHYSICAL,PAGE_READWRITE);//将分配的页面大小向上取整到页面大小整数倍SYSTEM_INFO si;GetSystemInfo(&si);ULONG_PTR ulPageNum=(ulWindowSize+si.dwPageSize-1)/si.dwPageSize;//分配一个页面数量大小的数组,保存页框号ULONG_PTR* pPageFrame=(ULONG_PTR*)new ULONG_PTR(ulPageNum);//分配物理内存块//只能为当前进程分配物理内存块//ulPageNum(in,out),函数调用完毕会返回实际分配的页面大小,一般此值不会改变//调用者必须具有锁定内存权限AllocateUserPhysicalPages(GetCurrentProcess(),&ulPageNum,pPageFrame);//将分配的物理内存块映射到地址窗口MapUserPhysicalPages(pWindow,ulPageNum,pPageFrame);//这里就可以使用pWindow指针了//可以使用如下调用撤销为地址窗口映射的物理内存块//MapUserPhysicalPages(pWindow,ulPageNum,NULL);//释放内存块FreeUserPhysicalPages(GetCurrentProcess(),&ulPageNum,pPageFrame);//释放地址窗口VirtualFree(pWindow,0,MEM_RELEASE);//释放页框号数组delete[] pPageFrame;
原创粉丝点击