全面介绍Windows内存管理机制及C++内存分配实例(三):虚拟内存
本文背景:
在編程中,很多Windows或C++的內(nèi)存函數(shù)不知道有什么區(qū)別,更別談?dòng)行褂?#xff1b;根本的原因是,沒(méi)有清楚的理解操作系統(tǒng)的內(nèi)存管理機(jī)制,本文企圖通過(guò)簡(jiǎn)單的總結(jié)描述,結(jié)合實(shí)例來(lái)闡明這個(gè)機(jī)制。
本文目的:
對(duì)Windows內(nèi)存管理機(jī)制了解清楚,有效的利用C++內(nèi)存函數(shù)管理和使用內(nèi)存。
本文內(nèi)容:
本文一共有六節(jié),由于篇幅較多,故按節(jié)發(fā)表。其他章節(jié)請(qǐng)看本人博客的Windows內(nèi)存管理及C++內(nèi)存分配實(shí)例(一)(二)(四)(五)和(六)。
?
3.??????內(nèi)存管理機(jī)制--虛擬內(nèi)存?(VM)
·????????虛擬內(nèi)存使用場(chǎng)合
虛擬內(nèi)存最適合用來(lái)管理大型對(duì)象或數(shù)據(jù)結(jié)構(gòu)。比如說(shuō),電子表格程序,有很多單元格,但是也許大多數(shù)的單元格是沒(méi)有數(shù)據(jù)的,用不著分配空間。也許,你會(huì)想到用動(dòng)態(tài)鏈表,但是訪問(wèn)又沒(méi)有數(shù)組快。定義二維數(shù)組,就會(huì)浪費(fèi)很多空間。
它的優(yōu)點(diǎn)是同時(shí)具有數(shù)組的快速和鏈表的小空間的優(yōu)點(diǎn)。
?
·????????分配虛擬內(nèi)存
如果你程序需要大塊內(nèi)存,你可以先保留內(nèi)存,需要的時(shí)候再提交物理存儲(chǔ)器。在需要的時(shí)候再提交才能有效的利用內(nèi)存。一般來(lái)說(shuō),如果需要內(nèi)存大于1M,用虛擬內(nèi)存比較好。
?
·????????保留
用以下Windows?函數(shù)保留內(nèi)存塊
VirtualAlloc (PVOID?開(kāi)始地址,SIZE_T?大小,DWORD?類型,DWORD?保護(hù)屬性)
一般情況下,你不需要指定“開(kāi)始地址”,因?yàn)槟悴恢肋M(jìn)程的那段空間是不是已經(jīng)被占用了;所以你可以用NULL。“大小”是你需要的內(nèi)存字節(jié);“類型”有MEM_RESERVE(保留)、MEM_RELEASE(釋放)和MEM_COMMIT(提交)?!氨Wo(hù)屬性”在前面章節(jié)有詳細(xì)介紹,只能用前六種屬性。
如果你要保留的是長(zhǎng)久不會(huì)釋放的內(nèi)存區(qū),就保留在較高的空間區(qū)域,這樣不會(huì)產(chǎn)生碎片。用這個(gè)類型標(biāo)志可以達(dá)到:
MEM_RESERVE|MEM_TOP_DOWN。
C++程序:保留1G的空間
LPVOID pV=VirtualAlloc(NULL,1000*1024*1024,MEM_RESERVE|MEM_TOP_DOWN,PAGE_READWRITE);?
????????????if(pV==NULL)
????????????cout<<"沒(méi)有那么多虛擬空間!"<<endl;
????????????MEMORYSTATUS memStatusVirtual1;
????????????GlobalMemoryStatus(&memStatusVirtual1);
????????????cout<<"虛擬內(nèi)存分配:"<<endl;
????????????printf("指針地址=%x/n",pV);
cout<<"減少物理內(nèi)存="<<memStatusVirtual.dwAvailPhys-memStatusVirtual1.dwAvailPhys<<endl;
cout<<"減少可用頁(yè)文件="<<memStatusVirtual.dwAvailPageFile-memStatusVirtual1.dwAvailPageFile<<endl;
cout<<"減少可用進(jìn)程空間="
<<memStatusVirtual.dwAvailVirtual-memStatusVirtual1.dwAvailVirtual<<endl<<endl;
結(jié)果如下:
?
可見(jiàn),進(jìn)程空間減少了1G;減少的物理內(nèi)存和可用頁(yè)文件用來(lái)管理頁(yè)目和頁(yè)表。但是,現(xiàn)在訪問(wèn)空間的話,會(huì)出錯(cuò)的:
int?* iV=(int*)pV;
???//iV[0]=1;現(xiàn)在訪問(wèn)會(huì)出錯(cuò),出現(xiàn)訪問(wèn)違規(guī)
?
·????????提交
你必須提供一個(gè)初始地址和提交的大小。提交的大小系統(tǒng)會(huì)變成頁(yè)面的倍數(shù),因?yàn)橹荒馨错?yè)面提交。指定類型是MEM_COMMIT。保護(hù)屬性最好跟區(qū)域的保護(hù)屬性一致,這樣可以提高系統(tǒng)管理的效率。
C++程序:提交100M的空間
LPVOID pP=VirtualAlloc(pV,100*1024*1024,MEM_COMMIT,PAGE_READWRITE);????
????????????if(pP==NULL)
????????????cout<<"沒(méi)有那么多物理空間!"<<endl;
????????????int?* iP=(int*)pP;
????????????iP[0]=3;
????????????iP[100/sizeof(int)*1024*1024-1]=5;//這是能訪問(wèn)的最后一個(gè)地址
????????????//iP[100/sizeof(int)*1024*1024]=5;訪問(wèn)出錯(cuò)
??
·????????保留&提交
你可以用類型MEM_RESERVE|MEM_COMMIT一次全部提交。但是這樣的話,沒(méi)有有效地利用內(nèi)存,和使用一般的C++動(dòng)態(tài)分配內(nèi)存函數(shù)一樣了。
?
·????????更改保護(hù)屬性
更改已經(jīng)提交的頁(yè)面的保護(hù)屬性,有時(shí)候會(huì)很有用處,假設(shè)你在訪問(wèn)數(shù)據(jù)后,不想別的函數(shù)再訪問(wèn),或者出于防止指針亂指改變結(jié)構(gòu)的目的,你可以更改數(shù)據(jù)所處的頁(yè)面的屬性,讓別人無(wú)法訪問(wèn)。
VirtualProtect (PVOID?基地址,SIZE_T?大小,DWORD?新屬性,DWORD?舊屬性)
“基地址”是你想改變的頁(yè)面的地址,注意,不能跨區(qū)改變。
C++程序:更改一頁(yè)的頁(yè)面屬性,改為只讀,看看還能不能訪問(wèn)
DWORD protect;
????????????iP[0]=8;
????????????VirtualProtect(pV,4096,PAGE_READONLY,&protect);
????????????int?* iP=(int*)pV;
iP[1024]=9;//可以訪問(wèn),因?yàn)樵谀且豁?yè)之外
????????????//iP[0]=9;不可以訪問(wèn),只讀
????????????//還原保護(hù)屬性
????????????VirtualProtect(pV,4096,PAGE_READWRITE,&protect);
???cout<<"初始值="<<iP[0]<<endl;//可以訪問(wèn)
?
·????????清除物理存儲(chǔ)器內(nèi)容
清除頁(yè)面指的是,將頁(yè)面清零,也就是說(shuō)當(dāng)作頁(yè)面沒(méi)有改變。假設(shè)數(shù)據(jù)存在物理內(nèi)存中,系統(tǒng)沒(méi)有RAM頁(yè)面后,會(huì)將這個(gè)頁(yè)面暫時(shí)寫進(jìn)虛擬內(nèi)存頁(yè)文件中,這樣來(lái)回的倒騰系統(tǒng)會(huì)很慢;如果那一頁(yè)數(shù)據(jù)已經(jīng)不需要的話,系統(tǒng)可以直接使用。當(dāng)程序需要它那一頁(yè)時(shí),系統(tǒng)會(huì)分配另一頁(yè)給它。
VirtualAlloc (PVOID?開(kāi)始地址,SIZE_T?大小,DWORD?類型,DWORD?保護(hù)屬性)
“大小”如果小于一個(gè)頁(yè)面的話,函數(shù)會(huì)執(zhí)行失敗,因?yàn)橄到y(tǒng)使用四舍五入的方法;“類型”是MEM_RESET。
有人說(shuō),為什么需要清除呢,釋放不就行了嗎?你要知道,釋放了后,程序就無(wú)法訪問(wèn)了?,F(xiàn)在只是因?yàn)椴恍枰Y(jié)構(gòu)的內(nèi)容了,順便提高一下系統(tǒng)的性能;之后程序仍然需要訪問(wèn)這個(gè)結(jié)構(gòu)的。
C++程序:
清除1M的頁(yè)面:
PVOID re=VirtualAlloc(pV,1024*1024,MEM_RESET,PAGE_READWRITE);
????????????if(re==NULL)
???cout<<"清除失敗!"<<endl;
這時(shí)候,頁(yè)面可能還沒(méi)有被清零,因?yàn)槿绻到y(tǒng)沒(méi)有RAM請(qǐng)求的話,頁(yè)面內(nèi)存保存不變的,為了看看被清零的效果,程序人為的請(qǐng)求大量頁(yè)面:
C++程序:
VirtualAlloc((char*)pV+100*1024*1024+4096,memStatus.dwAvailPhys+10000000,MEM_COMMIT,PAGE_READWRITE);//沒(méi)訪問(wèn)之前是不給物理內(nèi)存的。???
????????????char* pp=(char*)pV+100*1024*1024+4096;
????????????for(int?i=0;i<memStatus.dwAvailPhys+10000000;i++)
????????????pp[i]='V';//逼他使用物理內(nèi)存,而不使用頁(yè)文件
????????????GlobalMemoryStatus(&memStatus);
????????????cout<<"內(nèi)存初始狀態(tài):"<<endl;
????????????cout<<"長(zhǎng)度="<<memStatus.dwLength<<endl;
????????????cout<<"內(nèi)存繁忙程度="<<memStatus.dwMemoryLoad<<endl;
????????????cout<<"總物理內(nèi)存="<<memStatus.dwTotalPhys<<endl;
????????????cout<<"可用物理內(nèi)存="<<memStatus.dwAvailPhys<<endl;
????????????cout<<"總頁(yè)文件="<<memStatus.dwTotalPageFile<<endl;
????????????cout<<"可用頁(yè)文件="<<memStatus.dwAvailPageFile<<endl;
????????????cout<<"總進(jìn)程空間="<<memStatus.dwTotalVirtual<<endl;
????????????cout<<"可用進(jìn)程空間="<<memStatus.dwAvailVirtual<<end;
???cout<<"清除后="<<iP[0]<<endl;
結(jié)果如下:
?
當(dāng)內(nèi)存所剩無(wú)幾時(shí),系統(tǒng)將剛清除的內(nèi)存頁(yè)面分配出去,同時(shí)不會(huì)把頁(yè)面的內(nèi)存寫到虛擬頁(yè)面文件中。可以看見(jiàn),原先是8的值現(xiàn)在是0了。
?
·????????虛擬內(nèi)存的關(guān)鍵之處
虛擬內(nèi)存存在的優(yōu)點(diǎn)是,需要的時(shí)候才真正分配內(nèi)存。那么程序必須決定何時(shí)才提交內(nèi)存。
如果訪問(wèn)沒(méi)有提交內(nèi)存的數(shù)據(jù)結(jié)構(gòu),系統(tǒng)會(huì)產(chǎn)生訪問(wèn)違規(guī)的錯(cuò)誤。提交的最好方法是,當(dāng)你程序需要訪問(wèn)虛擬內(nèi)存的數(shù)據(jù)結(jié)構(gòu)時(shí),假設(shè)它已經(jīng)是分配內(nèi)存的,然后異常處理可能出現(xiàn)的錯(cuò)誤。對(duì)于訪問(wèn)違規(guī)的錯(cuò)誤,就提交這個(gè)地址的內(nèi)存。
?
·????????釋放
可以釋放整個(gè)保留的空間,或者只釋放分配的一些物理內(nèi)存。
釋放特定分配的物理內(nèi)存:
如果不想釋放所有空間,可以只釋放某些物理內(nèi)存。
“開(kāi)始地址”是頁(yè)面的基地址,這個(gè)地址不一定是第一頁(yè)的地址,一個(gè)竅門是提供一頁(yè)中的某個(gè)地址就行了,因?yàn)橄到y(tǒng)會(huì)做頁(yè)邊界處理,取該頁(yè)的首地址;“大小”是頁(yè)面的要釋放的字節(jié)數(shù);“類型”是MEM_DECOMMIT。
C++程序:
????????????//只釋放物理內(nèi)存
????????????VirtualFree((int*)pV+2000,50*1024*1024,MEM_DECOMMIT);
????????????int* a=(int*)pV;
????????????a[10]=2;//可以使用,沒(méi)有釋放這一頁(yè)
????????????MEMORYSTATUS memStatusVirtual3;
????????????GlobalMemoryStatus(&memStatusVirtual3);
????????????cout<<"物理內(nèi)存釋放:"<<endl;
cout<<"增加物理內(nèi)存="<<memStatusVirtual3.dwAvailPhys-memStatusVirtual2.dwAvailPhys<<endl;
cout<<"增加可用頁(yè)文件="<<memStatusVirtual3.dwAvailPageFile-memStatusVirtual2.dwAvailPageFile<<endl;
???cout<<"增加可用進(jìn)程空間="
<<memStatusVirtual3.dwAvailVirtual-memStatusVirtual2.dwAvailVirtual<<endl<<endl;
結(jié)果如下:
?
可以看見(jiàn),只釋放物理內(nèi)存,沒(méi)有釋放進(jìn)程的空間。
?
釋放整個(gè)保留的空間:
VirtualFree (LPVOID?開(kāi)始地址,SIZE_T?大小,DWORD?類型)
“開(kāi)始地址”一定是該區(qū)域的基地址;“大小”必須是0,因?yàn)橹荒茚尫耪麄€(gè)保留的空間;“類型”是MEM_RELEASE。
C++程序:
VirtualFree(pV,0,MEM_RELEASE);
????????????//a[10]=2;不能使用了,進(jìn)程空間也釋放了
?
????????????MEMORYSTATUS memStatusVirtual4;
????????????GlobalMemoryStatus(&memStatusVirtual4);
????????????cout<<"虛擬內(nèi)存釋放:"<<endl;
cout<<"增加物理內(nèi)存="<<memStatusVirtual4.dwAvailPhys-memStatusVirtual3.dwAvailPhys <<endl;
cout<<"增加可用頁(yè)文件="<<memStatusVirtual4.dwAvailPageFile-memStatusVirtual3.dwAvailPageFile<<endl;
cout<<"增加可用進(jìn)程空間="
<<memStatusVirtual4.dwAvailVirtual-memStatusVirtual3.dwAvailVirtual<<endl<<endl;
結(jié)果如下:
?
整個(gè)分配的進(jìn)程區(qū)域被釋放了,包括所占的物理內(nèi)存和頁(yè)文件。
?
·????????何時(shí)釋放
如果數(shù)組的元素大小是小于一個(gè)頁(yè)面4K的話,你需要記錄哪些空間不需要,哪些在一個(gè)頁(yè)面上,可以用一個(gè)元素一個(gè)Bit來(lái)記錄;另外,你可以創(chuàng)建一個(gè)線程定時(shí)檢測(cè)無(wú)用單元。
?
·????????擴(kuò)展地址AWE
AWE是內(nèi)存管理器功能的一套應(yīng)用程序編程接口?(API)?,它使程序能夠?qū)⑽锢韮?nèi)存保留為非分頁(yè)內(nèi)存,然后將非分頁(yè)內(nèi)存部分動(dòng)態(tài)映射到程序的內(nèi)存工作集。此過(guò)程使內(nèi)存密集型程序(如大型數(shù)據(jù)庫(kù)系統(tǒng))能夠?yàn)閿?shù)據(jù)保留大量的物理內(nèi)存,而不必交換分頁(yè)文件以供使用。相反,數(shù)據(jù)在工作集中進(jìn)行交換,并且保留的內(nèi)存超過(guò)?4 GB?范圍。
對(duì)于物理內(nèi)存小于2G進(jìn)程空間時(shí),它的作用是:不必要在物理內(nèi)存和虛擬頁(yè)文件中交換。
對(duì)于物理內(nèi)存大于2G進(jìn)程空間時(shí),它的作用是:應(yīng)用程序能夠訪問(wèn)的物理內(nèi)存大于2G,也就相當(dāng)于進(jìn)程空間超越了2G的范圍;同時(shí)具有上述優(yōu)點(diǎn)。
3GB
當(dāng)在boot.ini?上加上?/3GB?選項(xiàng)時(shí),應(yīng)用程序的進(jìn)程空間增加了1G,也就是說(shuō),你寫程序時(shí),可以分配的空間又增大了1G,而不管物理內(nèi)存是多少,反正有虛擬內(nèi)存的頁(yè)文件,大不了慢點(diǎn)。
PAE
當(dāng)在boot.ini上加上?/PAE?選項(xiàng)時(shí),操作系統(tǒng)可以支持大于4G的物理內(nèi)存,否則,你加再多內(nèi)存操作系統(tǒng)也是不認(rèn)的,因?yàn)楣芾磉@么大的內(nèi)存需要特殊處理。所以,你內(nèi)存小于4G是沒(méi)有必要加這個(gè)選項(xiàng)的。注意,當(dāng)要支持大于16G的物理內(nèi)存時(shí),不能使用/3G選項(xiàng),因?yàn)?#xff0c;只有1G的系統(tǒng)空間是不能管理超過(guò)16G的內(nèi)存的。
AWE
當(dāng)在boot.ini上加上?/AWE選項(xiàng)時(shí),應(yīng)用程序可以為自己保留物理內(nèi)存,直接的使用物理內(nèi)存而不通過(guò)頁(yè)文件,也不會(huì)被頁(yè)文件交換出去。當(dāng)內(nèi)存大于3G時(shí),就顯得特別有用。因?yàn)榭梢猿浞掷梦锢韮?nèi)存。
當(dāng)物理內(nèi)存大于4G時(shí),需要/PAE的支持。
以下是一個(gè)boot.ini的實(shí)例圖,是我機(jī)器上的:
?
?
?
要使用AWE,需要用戶具有Lock Pages in Memory權(quán)限,這個(gè)在控制面板中的本地計(jì)算機(jī)政策中設(shè)置。
第一,分配進(jìn)程虛擬空間:
VirtualAlloc (PVOID?開(kāi)始地址,SIZE_T?大小,DWORD?類型,DWORD?保護(hù)屬性)
“開(kāi)始地址”可以是NULL,由系統(tǒng)分配進(jìn)程空間;“類型”是MEM_RESERVE|MEM_PHYSICAL;“保護(hù)屬性”只能是
PAGE_READWRITE。
MEM_PHYSICAL指的是區(qū)域?qū)⑹芪锢泶鎯?chǔ)器的支持。
第二,你要計(jì)算出分配的頁(yè)面數(shù)目PageCount:
利用本文第二節(jié)的GetSystemInfo可以計(jì)算出來(lái)。
第三,分配物理內(nèi)存頁(yè)面:
AllocateUserPhysicalPages (HANDLE?進(jìn)程句柄,SIZE_T?頁(yè)數(shù),ULONG_PTR?頁(yè)面指針數(shù)組)
進(jìn)程句柄可以用GetCurrentProcess()獲得;頁(yè)數(shù)是剛計(jì)算出來(lái)的頁(yè)數(shù)PageCount;頁(yè)面數(shù)組指針unsigned long* Array[PageCount]。
系統(tǒng)會(huì)將分配結(jié)果存進(jìn)這個(gè)數(shù)組。
第四,將物理內(nèi)存與虛擬空間進(jìn)行映射:
MapUserPhysicalPages (PVOID?開(kāi)始地址,SIZE_T?頁(yè)數(shù),ULONG_PTR?頁(yè)面指針數(shù)組)
“開(kāi)始地址”是第一步分配的空間;
這樣的話,虛擬地址就可以使用了。
如果“頁(yè)面指針數(shù)組”是NULL,則取消映射。
第五,釋放物理頁(yè)面
FreeUserPhysicalPages (HANDLE?進(jìn)程句柄,SIZE_T?頁(yè)數(shù),ULONG_PTR?頁(yè)面指針數(shù)組)
這個(gè)除了釋放物理頁(yè)面外,還會(huì)取消物理頁(yè)面的映射。
第六,釋放進(jìn)程空間
VirtualFree (PVOID?開(kāi)始地址,0,MEM_RELEASE)
?
C++程序:
首先,在登錄用戶有了Lock Pages in Memory權(quán)限以后,還需要調(diào)用Windows API激活這個(gè)權(quán)限。
BOOL VirtualMem::LoggedSetLockPagesPrivilege ( HANDLE hProcess,BOOL bEnable)?????????????????????
{
????????????struct?{
????????????????????????DWORD Count;//數(shù)組的個(gè)數(shù)
????????????????????????LUID_AND_ATTRIBUTES Privilege [1];} Info;
????????????HANDLE Token;
????????????//打開(kāi)本進(jìn)程的權(quán)限句柄
????????????BOOL Result = OpenProcessToken ( hProcess,
????????????????????????TOKEN_ADJUST_PRIVILEGES,
????????????????????????& Token);
????????????If?(Result!= TRUE )
????????????{
????????????????????????printf( "Cannot open process token./n" );
????????????????????????return?FALSE;
????????????}
????????????//我們只改變一個(gè)屬性
????????????Info.Count = 1;
????????????//準(zhǔn)備激活
????????????if( bEnable )
????????????????????Info.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED;
????????????else
????????????????????????Info.Privilege[0].Attributes = 0;
????????????//根據(jù)權(quán)限名字找到LGUID
????????????Result = LookupPrivilegeValue ( NULL,
????????????????????????SE_LOCK_MEMORY_NAME,
????????????????????????&(Info.Privilege[0].Luid));
????????????if( Result != TRUE )
????????????{
????????????????????????printf( "Cannot get privilege for %s./n", SE_LOCK_MEMORY_NAME );
????????????????????????return?FALSE;
????????????}
????????????//?激活Lock Pages in Memory權(quán)限
Result = AdjustTokenPrivileges ( Token, FALSE,(PTOKEN_PRIVILEGES) &Info,0, NULL, NULL);
????????????if( Result != TRUE )
????????????{
????????????????????????printf ("Cannot adjust token privileges (%u)/n", GetLastError() );
????????????????????????return?FALSE;
????????????}
????????????else
????????????{
????????????????????????if( GetLastError() != ERROR_SUCCESS )
????????????????????????{
printf ("Cannot enable the SE_LOCK_MEMORY_NAME privilege; ");
????????????????????????????????????printf ("please check the local policy./n");
????????????????????????????????????return?FALSE;
????????????????????????}
????????????}
????????????CloseHandle( Token );
????????????return?TRUE;
}
?
分配100M虛擬空間:
PVOID pVirtual=VirtualAlloc(NULL,100*1024*1024,MEM_RESERVE|MEM_PHYSICAL,PAGE_READWRITE);
????????????if(pVirtual==NULL)
????????????????????????cout<<"沒(méi)有那么大連續(xù)進(jìn)程空間!"<<endl;
?
????????????MEMORYSTATUS memStatusVirtual5;
????????????GlobalMemoryStatus(&memStatusVirtual5);
????????????cout<<"虛擬內(nèi)存分配:"<<endl;
cout<<"減少物理內(nèi)存="<<memStatusVirtual4.dwAvailPhys-memStatusVirtual5.dwAvailPhys<<endl
cout<<"減少可用頁(yè)文件="<<memStatusVirtual4.dwAvailPageFile-memStatusVirtual5.dwAvailPageFile<<endl;
???cout<<"減少可用進(jìn)程空間="
<<memStatusVirtual4.dwAvailVirtual-memStatusVirtual5.dwAvailVirtual<<endl<<endl;
結(jié)果如下:
?
可以看見(jiàn),只分配了進(jìn)程空間,沒(méi)有分配物理內(nèi)存。
?
分配物理內(nèi)存:
ULONG_PTR pages=(ULONG_PTR)100*1024*1024/sysInfo.dwPageSize;
????????????ULONG_PTR *frameArray=new?ULONG_PTR[pages];
????????????//如果沒(méi)激活權(quán)限,是不能調(diào)用這個(gè)方法的,可以調(diào)用,但是返回FALSE
BOOL flag=AllocateUserPhysicalPages(GetCurrentProcess(),
&pages,frameArray);
????????????if(flag==FALSE)
????????????????????????cout<<"分配物理內(nèi)存失敗!"<<endl;
????????????MEMORYSTATUS memStatusVirtual6;
????????????GlobalMemoryStatus(&memStatusVirtual6);
????????????cout<<"物理內(nèi)存分配:"<<endl;
cout<<"減少物理內(nèi)存="<<memStatusVirtual5.dwAvailPhys-memStatusVirtual6.dwAvailPhys<<endl
cout<<"減少可用頁(yè)文件="<<memStatusVirtual5.dwAvailPageFile-memStatusVirtual6.dwAvailPageFile<<endl;
cout<<"減少可用進(jìn)程空間="<<memStatusVirtual5.dwAvailVirtual-memStatusVirtual6.dwAvailVirtual<<endl<<endl;
??結(jié)果如下:
?
分配了物理內(nèi)存,可能分配時(shí)需要進(jìn)程空間管理。
?
物理內(nèi)存映射進(jìn)程空間:
int* pVInt=(int*)pVirtual;
????????????//pVInt[0]=10;這時(shí)候訪問(wèn)會(huì)出錯(cuò)
????????????flag=MapUserPhysicalPages(pVirtual,1,frameArray);
????????????if(flag==FALSE)
????????????????????????cout<<"映射物理內(nèi)存失敗!"<<endl;
????????????MEMORYSTATUS memStatusVirtual7;
????????????GlobalMemoryStatus(&memStatusVirtual7);
????????????cout<<"物理內(nèi)存分配:"<<endl;
cout<<"減少物理內(nèi)存="<<memStatusVirtual6.dwAvailPhys-memStatusVirtual7.dwAvailPhys<<endl
cout<<"減少可用頁(yè)文件="<<memStatusVirtual6.dwAvailPageFile-memStatusVirtual7.dwAvailPageFile<<endl;
cout<<"減少可用進(jìn)程空間="
<<memStatusVirtual6.dwAvailVirtual-memStatusVirtual7.dwAvailVirtual<<endl<<endl;
結(jié)果如下:
?
這個(gè)過(guò)程沒(méi)有損失任何東西。
?
看看第一次映射和第二次映射的值:
pVInt[0]=10;
????????????cout<<"第一次映射值="<<pVInt[0]<<endl;
????????????????????????flag=MapUserPhysicalPages(pVirtual,1,frameArray+1);
????????????if(flag==FALSE)
????????????????????????cout<<"映射物理內(nèi)存失敗!"<<endl;
????????????pVInt[0]=21;
????????????cout<<"第二次映射值="<<pVInt[0]<<endl;
????????????flag=MapUserPhysicalPages(pVirtual,1,frameArray);
????????????if(flag==FALSE)
????????????????????????cout<<"映射物理內(nèi)存失敗!"<<endl;
????????????cout<<"再現(xiàn)第一次映射值="<<pVInt[0]<<endl;
結(jié)果如下:
?
可以看出,第二次映射的值沒(méi)有覆蓋第一次映射的值,也就是說(shuō),用同一個(gè)進(jìn)程空間地址可以取出兩份數(shù)據(jù),這樣的話,相當(dāng)于進(jìn)程的地址空間增大了。
?
總結(jié)
以上是生活随笔為你收集整理的全面介绍Windows内存管理机制及C++内存分配实例(三):虚拟内存的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【BZOJ】3139: [Hnoi201
- 下一篇: C++11 并发指南六(atomic 类