本节介绍如何使用虚拟内存功能进行动态分配。
以下示例说明了VirtualAlloc和VirtualFree函数根据动态数组的需要预留和提交内存时的使用。首先,VirtualAlloc被调用来保留一个被指定为NULL地址参数的页面块,从而迫使内核确定块的位置。稍后,只要有必要从该保留区域提交页面,就会调用VirtualAlloc,并指定要提交的下一页的基址。
该示例使用尝试 - 除结构化异常处理语法来从保留区域提交页面。每当执行尝试块期间发生页错误异常时,将执行除块之前的表达式中的过滤器函数。如果过滤器功能可以分配另一个页面,则在发生异常的时候,在尝试块中继续执行。否则,将执行除块中的异常处理程序。有关结构化异常处理的更多信息,请参阅结构化异常处理.
作为动态分配的替代方法,该过程可以简单地提交整个区域,而不仅仅是保留它。但是,提交该区域将消耗可能不需要的物理存储,从而使其不能被其他进程使用。
该示例使用VirtualFree完成保留和提交的页面后,释放它们。该函数被调用两次:首先解除提交的页面,并再次释放保留页面的整个区域。
#define PAGESIZE 0x1000
/* Reserve pages in the process's virtual address space.
INT PageFaultExceptionFilter(DWORD);
VOID MyErrorExit(LPTSTR);
LPTSTR lpNxtPage;
DWORD dwPages = 0;
VOID UseDynamicVirtualAlloc(VOID){
LPVOID lpvBase;
LPTSTR lpPtr;
BOOL bSuccess;
DWORD i;
/ *保留进程虚拟地址空间中的页面。*/
lpvBase = VirtualAlloc(
NULL,/ *系统选择地址* /
PAGELIMIT * PAGESIZE,/ *大小分配* /
MEM_RESERVE,/ *分配保留页面* /
PAGE_NOACCESS); /* protection = no access */
if (lpvBase == NULL )
MyErrorExit("VirtualAlloc reserve");
lpPtr = lpNxtPage = (LPTSTR) lpvBase;
/*
*使用try-except结构化异常处理时
*访问页面。如果发生页错误,
*执行异常过滤器以提交另一个页面
*从预留的页面块。
*/
for (i=0; i < PAGELIMIT*PAGESIZE; i++) {
尝试{
/ *写入内存。*/
lpPtr[i] = 'a';
}
/*
*如果有页面错误,请提交另一个页面
* 然后再试一次。
*/
except(PageFaultExceptionFilter(
GetExceptionCode())){
/*
*只有过滤功能才执行
*提交下一页不成功。
*/
ExitProcess( GetLastError() );
}
}
/ *完成使用后,释放页面块。*/
/ *首先,解决承诺的页面。*/
bSuccess = VirtualFree(
lpvBase,/ *块的地址* /
dwPages * PAGESIZE,/ *已提交页面的字节* /
MEM_DECOMMIT); /* decommit the pages */
/ *释放整个块。*/
如果(bSuccess)
bSuccess = VirtualFree(
lpvBase,/ *块的地址* /
0,/ *释放整个块* /
MEM_RELEASE); /* releases the pages */
}
INT PageFaultExceptionFilter(DWORD dwCode){
LPVOID lpvResult;
/ *如果异常不是页面错误,请退出。*/
if (dwCode != EXCEPTION_ACCESS_VIOLATION) {
printf("exception code = %d\n", dwCode);
return EXCEPTION_EXECUTE_HANDLER;
}
printf("page fault\n");
/ *如果预留页面用完,请退出。*/
if (dwPages >= PAGELIMIT) {
printf("out of pages\n");
return EXCEPTION_EXECUTE_HANDLER;
}
/ *否则,提交另一个页面。*/
lpvResult = VirtualAlloc(
(LPVOID)lpNxtPage,/ *下一页提交* /
PAGESIZE,/ *页面大小,以字节为单位* /
MEM_COMMIT,/ * alloc commit page * /
PAGE_READWRITE); /* read-write access */
if (lpvResult == NULL ) {
printf("VirtualAlloc failed\n");
return EXCEPTION_EXECUTE_HANDLER;
}
/*
*增加页数,并提高lpNxtPage
*到下一页。
*/
dwPages++;
lpNxtPage += PAGESIZE;
/ *继续执行页面发生故障。*/
return EXCEPTION_CONTINUE_EXECUTION;
}