




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
1、全面介紹Windows內存管理機制及C+內存分配實例(一):進程空間在編程中,很多Windows或C+的內存函數不知道有什么區別,更別談有效使用;根本的原因是,沒有清楚的理解操作系統的內存管理機制,本文企圖通過簡單的總結描述,結合實例來闡明這個機制。本文目的:對Windows內存管理機制了解清楚,有效的利用C+內存函數管理和使用內存。本文內容:本文一共有六節,由于篇幅較多,故按節發表。其他章節請看本人博客的Windows內存管理及C+內存分配實例(二)(三)(四)(五)和(六)。1. 進程地址空間地址空間
2、0; 32|64位的系統|CPU 操作系統運行在硬件CPU上,32位操作系統運行于32位CPU上,64位操作系統運行于64位CPU上;目前沒有真正的64位CPU。32位CPU一次只能操作32位二進制數;位數多CPU設計越復雜,軟件設計越簡單。 軟件的進程運行于32位系統上,其尋址位也是32位,能表示的空間是232=4G,范圍從0x0000 00000x
3、FFFF FFFF。 NULL指針分區范圍:0x0000 00000x0000 FFFF作用:保護內存非法訪問例子:分配內存時,如果由于某種原因分配不成功,則返回空指針0x0000 0000;當用戶繼續使用比如改寫數據時,系統將因為發生訪問違規而退出。 那么,為什么需要那么大的區域呢,一個地址值不就行了嗎?我在想,是不是因為不讓8或16位的程序運行于32位的系統上呢?!因為NULL分區剛好范圍是16的進程空間
4、。 獨享用戶分區范圍:0x0001 00000x7FFE FFFF作用:進程只能讀取或訪問這個范圍的虛擬地址;超越這個范圍的行為都會產生違規退出。例子: 程序的二進制代碼中所用的地址大部分將在這個范圍,所有exe和dll文件都加載到這個。每個進程將近2G的空間是獨享的。注意:如果在上設置了/3G,這個區域的范圍從2G擴大為3G:0x0001 00000xBFFE FFFF。
5、 共享內核分區范圍:0x8000 00000xFFFF FFFF作用:這個空間是供操作系統內核代碼、設備驅動程序、設備I/O高速緩存、非頁面內存池的分配、進程目表和頁表等。例子: 這段地址各進程是可以共享的。
6、
7、
8、 注意:如果在上設置了/3G,這個區域的范圍從2G縮小為1G:0xC000 00000xFFFF FFFF。 通過以上分析,可以知道,如果系統有n個進程,它所需的虛擬空間是:2G*n+2G (內核只需2G的共享空間。 地址映射
9、0;區域區域指的是上述地址空間中的一片連續地址。區域的大小必須是粒度(64k 的整數倍,不是的話系統自動處理成整數倍。不同CPU粒度大小是不一樣的,大部分都是64K。區域的狀態有:空閑、私有、映射、映像。在你的應用程序中,申請空間的過程稱作保留(預訂,可以用VirtualAlloc;刪除空間的過程為釋放,可以用VirtualFree。 在程序里預訂了地址空間以后,你還不可以存取數據,因為你還沒有付錢,沒有真實的RAM和它關聯。這時候的區域狀態是私有;默認情況下,區域狀態是空閑;當exe或DL
10、L文件被映射進了進程空間后,區域狀態變成映像;當一般數據文件被映射進了進程空間后,區域狀態變成映射。 物理存儲器Windows各系列支持的內存上限是不一樣的,從2G到64G不等。理論上32位CPU,硬件上只能支持4G內存的尋址;能支持超過4G的內存只能靠其他技術來彌補。順便提一下,Windows個人版只能支持最大2G內存,Intel使用Address Windows Extension (AWE 技術使得尋址范圍為236=64G。當然,也得操作系統配合。 &
11、#160; 內存分配的最小單位是4K或8K,一般來說,根據CPU不同而不同,后面你可以看到可以通過系統函數得到區域粒度和頁面粒度。 頁文件頁文件是存在硬盤上的系統文件,它的大小可以在系統屬性里面設置,它相當于物理內存,所以稱為虛擬內存。事實上,它的大小是影響系統快慢的關鍵所在,如果物理內存不多的情況下。 每頁的大小和上述所說內存分配的最小單位是一樣的,通常是4K或8K。
12、60; 訪問屬性物理頁面的訪問屬性指的是對頁面進行的具體操作:可讀、可寫、可執行。CPU一般不支持可執行,它認為可讀就是可執行。但是,操作系統提供這個可執行的權限。PAGE_NOACCESSPAGE_READONLYPAGE_READWRITEPAGE_EXECUTEPAGE_EXECUTE_READPAGE_EXECUTE_READWRITE這6個屬性很好理解,第一個是拒絕所有操作,最后一個是接受收有操作;PAGE_WRITECOPYPAGE_EXECUTE_WRITECOPY這兩個屬性在運行同一個程序的多個實
13、例時非常有用;它使得程序可以共享代碼段和數據段。一般情況下,多個進程只讀或執行頁面,如果要寫的話,將會Copy頁面到新的頁面。通過映射exe文件時設置這兩個屬性可以達到這個目的。PAGE_NOCACHEPAGE_WRITECOMBINE這兩個是開發設備驅動的時候需要的。PAGE_GUARD當往頁面寫入一個字節時,應用程序會收到堆棧溢出通知,在線程堆棧時有用。 映射過程進程地址空間的地址是虛擬地址,也就是說,當取到指令時,需要把虛擬地址轉化為物理地址才能夠存取數據。這個工作通過頁目和頁表進行。從圖中可以
14、看出,頁目大小為4K,其中每一項(32位保存一個頁表的物理地址;每個頁表大小為4K,其中每一項(32位保存一個物理頁的物理地址,一共有1024個頁表。利用這的空間可以表示進程的1024*1024* (一頁4K =4G的地址空間。進程空間中的32位地址如下:高10位用來找到1024個頁目項中的一項,取出頁表的物理地址后,利用中10位來得到頁表項的值,根據這個值得到物理頁的地址,由于一頁有4K大小,利用低12位得到單元地址,這樣就可以訪問這個內存單元了。 每個進程都有自己的一個頁目和頁表,那么,剛開始進程
15、是怎么找到頁目所在的物理頁呢?答案是CPU的CR3寄存器會保存當前進程的頁目物理地址。 當進程被創建時,同時需要創建頁目和頁表,一共需要。在進程的空間中,0xC030 00000xC030 0FFF是用來保存頁目的4k空間。0xC000 00000xC03F FFFF是用來保存頁表的4M空間。也就是說程序里面訪問這些地址你是可以讀取頁目和頁表的具體值的(要工作在內核方式下)。有一點我不明白的是,頁表的空間包含了頁目的空間!
16、0; 至于說,頁目和頁表是保存在物理內存還是頁文件中,我覺得,頁目比較常用,應該在物理內存的概率大點,頁表需要時再從頁文件導入物理內存中。 頁目項和頁表項是一個32位的值,當頁目項第0位為1時,表明頁表已經在物理內存中;當頁表項第0位為1時,表明訪問的數據已經在內存中。還有很多數據是否已經被改變,是否可讀寫等標志。另外,當頁目項第7位為1時,表明這是一個4M的頁面,這值已經是物理頁地址,用虛擬地址的低22位作為偏移量。還有很多:數據是否已經被改變、是否可讀寫等標志。 1.3
17、0;一個例子 編寫生成軟件程序exe軟件描述如下:Main (1:定義全局變量2:處理函數邏輯(Load 所需DLL庫,調用方法處理邏輯)3:定義并實現各種方法(方法含有局部變量) 4:程序結束將程序編譯,生成exe文件,
18、附帶所需的DLL庫。 exe文件格式exe文件有自己的格式,有若干節(section):.text用來放二進制代碼(exe或dll);.data用來放各種全局數據。.text指令1:move a, b指令2:add a, b.data數據1:a=2數據2:b=1這些地址都是虛擬地址,也就是進程的地址空間。 運行exe程序建立進程:運行這個exe程序時,系統會創建一個進程,建立進程控制塊PCB,生成進程頁目和頁
19、表,放到PCB中。 數據對齊:數據的內存地址除以數據的大小,余數為0時說明數據是對齊的。現在的編譯器編譯時就考慮數據對齊的問題,生成exe文件后,數據基本上是對齊的,CPU運行時,寄存器有標志標識CPU是否能夠自動對齊數據,如果遇到不能對齊的情況,或者通過兩次訪問內存,或者通知操作系統處理。要注意的是,如果數據沒有對齊,CPU處理的效率是很低的。 文件映射:系統不會將整個exe文件和所有的DLL文件裝載進物理內存中,同時它也不會裝載進頁面文件中。相反,它會建立文件映射,也就是利用exe本身當作頁面文件。系統將部分二進制代碼裝載進內存,分配頁面給它。 &
20、#160; 假設分配了一個頁面,物理地址為0x0232 FFF1。其中裝載的一個指令虛擬地址為0x4000 1001=0100 0000 00 0000 0000 01 0000 0000 0001。一個頁面有4K,系統會將指令保存在低12位0x0001的地址處。同時,系統根據高10位0x0100找到頁目項,如果沒有關聯的頁表,系統會生成一個頁表,分配一個物理頁;然后,根據中10位0x0001找到表項,將物理地址0x0232 FFF1存進去。 執行過程:執行時,當系統拿到一個虛擬地址,就根據頁目和頁表找到數
21、據的地址,根據頁目上的值可以判斷頁表是在頁文件中還是在內存中;如果在頁文件中,會將頁面導入內存,更新頁目項。讀取頁表項的值后,可以判斷數據頁文件中還是在物理內存中;如果在頁文件中,會導入到內存中,更新頁表項。最終,拿到了數據。 在分配物理頁的過程中,系統會根據內存分配的狀況適當淘汰暫時不用的頁面,如果頁面內容改變了(通過頁表項的標志位),保存到頁文件中,系統會維護內存與頁文件的對應關系。由于將exe文件當作內存映射文件,當需要改變數據,如更改全局變量的值時,利用Copy-On-Write的機制,重新生
22、成頁文件,將結果保存在這個頁文件中,原來的頁文件還是需要被其他進程實例使用的。 在清楚了指令和數據是如何導入內存,如何找到它們的情況下,剩下的就是CPU不斷的取指令、運行、保存數據的過程了,當進程結束后,系統會清空之前的各種結構、釋放相關的物理內存和刪除頁文件。 (二):內存狀態查詢2. 內存狀態查詢函數系統信息Windows 提供API可以查詢系統內存的一些屬性,有時候我們需要獲取一些頁
23、面大小、分配粒度等屬性,在分配內存時用的上。請看以下C+程序:SYSTEM_INFO sysInfo; GetSystemInfo(&sysInfo; cout<<"機器屬性:"<
24、160; cout<<"頁大小="< cout<<"分配粒度="< cout<<"用戶區最小值="< cout<
25、;<"用戶區最大值="< 結果如下: 可以看出,頁面大小是4K,區域分配粒度是64K,進程用戶區是0x0001 00000x7FFE FFFF。 內存狀態 內存狀態可以獲取總內存和可用內存,包括頁文件和物理內存。請看以下C+程序:MEMORYSTATUS memStatus; GlobalMemoryStatu
26、s(&memStatus; cout<<"內存初始狀態:"< cout<<"內存繁忙程度="< &
27、#160;cout<<"總物理內存="< cout<<"可用物理內存="< cout<<"總頁文件="<
28、0; cout<<"可用頁文件="< cout<<"總進程空間="< cout<<"可用進程空間="< 結果如下:可以看出,總物理內存是1G,可用物理內存是510兆,總頁文件是,這個是包含物理內存的頁文件;可用頁文件是。這里還標識了總進程空間,還有可用的進程空
29、間,程序只用了22兆的內存空間。這里說的都是大約數。內存繁忙程序是標識當前系統內存管理的繁忙程序,從0到100,其實用處不大。 在函數里面靜態分配一些內存后,看看究竟發生什么char stat65536; MEMORYSTATUS memStatus1;
30、160; GlobalMemoryStatus(&memStatus1; cout<<"靜態分配空間:"< printf("指針地址=%xn",stat;cout<<"減少物理內存
31、="< cout<<"減少可用頁文件="< cout<<"減少可用進程空間="< memSta tus1.dwAvailVirtual< 結果如下: 可以看出,物理內存、可用頁文件和進程空間都沒有損耗。因為局部變量是分配在線程堆棧里面的,每個線程系統都會建立一個默認1M大小的堆棧給線程函數調用使用。如果分配超過1M,就會出現堆棧溢出。 在函數里面動態分配300M的內存后,看看究竟發生
32、什么char *dynamic=new char300*1024*1024; MEMORYSTATUS memStatus2; GlobalMemoryStatus(&memStatus2; &
33、#160; cout<<"動態分配空間:"< printf("指針地址=%xn",dynamic;cout<<"減少物理內存="< cout<<"減少可用頁文件="< cout<<"減少可用進程空間="< 結果如下: 動態分配情況下,系統分
34、配直到內存頁文件使用完為止,當然,系統要留一下系統使用的頁面。 2.3 進程區域地址查詢在給定一個進程空間的地址后,可以查詢它所在區域和相鄰頁面的狀態,包括頁面保護屬性、存儲器類型等。 C+靜態分配了兩次內存,一次是4K大一點,一個是900K左右。char arrayA4097; char arrayB900000;第一次
35、查詢: long len=sizeof(MEMORY_BASIC_INFORMATION; MEMORY_BASIC_INFORMATION mbiA; Virtu
36、alQuery(arrayA,&mbiA,len; cout<<"靜態內存地址屬性:"< cout<<"區域基地址="<
37、 cout<<"區域鄰近頁面狀態="< cout<<"區域保護屬性="< cout<<"頁面基地址="<
38、; printf("arrayA指針地址=%xn",arrayA; cout<<"從頁面基地址開始的大小="< cout<<"鄰近頁面物理存儲器類型=&
39、quot;< cout<<"頁面保護屬性="< 第二次查詢: MEMORY_BASIC_INFORMATION mbiB; Vi
40、rtualQuery(arrayB,&mbiB,len; cout<<"靜態內存地址屬性:"< cout<<"區域基地址="<
41、60; cout<<"區域鄰近頁面狀態="< cout<<"區域保護屬性="< cout<<"頁面基地址="<
42、160; printf("arrayB指針地址=%xn",arrayB; cout<<"從頁面基地址開始的大小="< cout<<"鄰近頁面物理存儲器類
43、型="< cout<<"頁面保護屬性="< 說明:區域基地址指的是給定地址所在的進程空間區域;鄰近頁面狀態指的是與給定地址所在頁面狀態相同頁面的屬性:MEM_FREE(空閑=65536)、MEM_RESERVE(保留=8192)和MEM_COMMIT(提交=4096)。區域保護屬性指的是區域初次被保留時被賦予的保護屬性:PAGE_READONLY(2)、PAGE_READWRITE(4)、PAGE_WRITECOPY(8)和PAGE_EXECUTE_WRITECOPY(128)等等。頁面基地址
44、指的是給定地址所在頁面的基地址。從頁面基地址開始的區域頁面的大小,指的是與給定地址所在頁面狀態、保護屬性相同的頁面。鄰近頁面物理存儲器類型指的是與給定地址所在頁面相同的存儲器類型,包括:MEM_PRIVATE(頁文件=131072)、MEM_MAPPED(文件映射=262144)和MEM_IMAGE(exe映像=16777216)。頁面保護屬性指的是頁面被指定的保護屬性,在區域保護屬性指定后更新。 結果如下: 如前所說,這是在堆棧區域0x0004 0000里分配的,后分配的地址arrayB反而更小,符合堆棧的特性。arrayA和arrayB它們處于不同的頁面。頁面都受頁文件
45、支持,并且區域都是提交的,是系統在線程創建時提交的。 C+動態分配了兩次內存,一次是1K大一點,一個是64K左右。所以應該不會在一個區域。char *dynamicA=new char1024; char *dynamicB=new char65467;
46、; VirtualQuery(dynamicA,&mbiA,len; cout<<"動態內存地址屬性:"< cout<<"區域基地址="<
47、0; cout<<"區域鄰近頁面狀態="< cout<<"區域保護屬性="< cout<<&q
48、uot;頁面基地址="< printf("dynamicA指針地址=%xn",dynamicA; cout<<"從頁面基地址開始的大小="< &
49、#160; cout<<"鄰近頁面物理存儲器類型="< cout<<"頁面保護屬性="< VirtualQuery(dynamicB,&mbiB,len;
50、160; cout<<"動態內存地址屬性:"< cout<<"區域基地址="< cout<<"區域鄰近頁面狀
51、態="< cout<<"區域保護屬性="< cout<<"頁面基地址="<
52、printf("dynamicB指針地址=%xn",dynamicB; cout<<"從頁面基地址開始的大小="< cout<<"鄰近頁面物理存儲器類型="<
53、; cout<<"頁面保護屬性="< 結果如下: 這里是動態分配,dynamicA和dynamicB處于兩個不同的區域;同樣,頁面都受頁文件支持,并且區域都是提交的。第二個區域是比64K大的,由分配粒度可知,區域至少是128K。那么,剩下的空間也是提交的嗎,如果是的話那就太浪費了。看看就知道了:0x00E2 1000肯定在這個空間里,所以查詢如下:VirtualQuery(char*0xE23390,&mbiB,len; &
54、#160; cout<<"動態內存地址屬性:"< cout<<"區域基地址="< cout<<"
55、區域鄰近頁面狀態="< cout<<"區域保護屬性="< cout<<"頁面基地址="<
56、; printf("dynamicB指針地址=%xn",0xE21000; cout<<"從頁面基地址開始的大小="< cout<<"鄰近頁面物理存儲器類型="< cout
57、<<"頁面保護屬性="< 結果如下:可以看出,鄰近頁面狀態為保留,還沒提交,預料之中;0x00E1 0000 這個區域的大小可以計算出來:69632+978944=1024K。系統動態分配了1M的空間,就為了64K左右大小的空間。可能是為了使得下次有要求分配時時不用再分配了。 (三):虛擬內存3. 內存管理機制-虛擬內存 (VM 虛擬內存使用場合虛擬內存最適合用來管
58、理大型對象或數據結構。比如說,電子表格程序,有很多單元格,但是也許大多數的單元格是沒有數據的,用不著分配空間。也許,你會想到用動態鏈表,但是訪問又沒有數組快。定義二維數組,就會浪費很多空間。它的優點是同時具有數組的快速和鏈表的小空間的優點。 分配虛擬內存如果你程序需要大塊內存,你可以先保留內存,需要的時候再提交物理存儲器。在需要的時候再提交才能有效的利用內存。一般來說,如果需要內存大于1M,用虛擬內存比較好。
59、; 保留用以下Windows 函數保留內存塊VirtualAlloc (PVOID 開始地址,SIZE_T 大小,DWORD 類型,DWORD 保護屬性一般情況下,你不需要指定“開始地址”,因為你不知道進程的那段空間是不是已經被占用了;所以你可以用NULL。“大小”是你需要的內存字節;“類型”有MEM_RESERVE(保留)、MEM_RELEASE(釋放)和MEM_COMMIT(提交)。“保護屬性”在前面章節有詳細介紹,只能用前六種屬性。如果你要保留的是長久不會釋放的內存區,就保留在較高的空間區域,這樣不會產生碎片。用這個
60、類型標志可以達到: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<<
61、;"沒有那么多虛擬空間!"< MEMORYSTATUS memStatusVirtual1; GlobalMemoryStatus(&memStatusVirtual1; &
62、#160; cout<<"虛擬內存分配:"< printf("指針地址=%xn",pV;cout<<"減少物理內存="< cout<<"減少可用頁文件="< cout<<"減少可用進程空間="< 結果如下: 可見,進程空間減少了1G;減少的物理內存和可
63、用頁文件用來管理頁目和頁表。但是,現在訪問空間的話,會出錯的:int * iV=(int*pV; /iV0=1;現在訪問會出錯,出現訪問違規 提交你必須提供一個初始地址和提交的大小。提交的大小系統會變成頁面的倍數,因為只能按頁面提交。指定類型是MEM_COMMIT。保護屬性最好跟區域的保護屬性一致,這樣可以提高系統管理的效率。C+程序:提交100M的空間LPVOID pP=VirtualAlloc(pV,100*1024*1024,MEM_COM
64、MIT,PAGE_READWRITE; if(pP=NULL cout<<"沒有那么多物理空間!"<
65、0; int * iP=(int*pP; iP0=3; iP100/sizeof(int*1024*1024-1=5;/這是能訪問的最后一個地址 /iP1
66、00/sizeof(int*1024*1024=5;訪問出錯 保留&提交你可以用類型MEM_RESERVE|MEM_COMMIT一次全部提交。但是這樣的話,沒有有效地利用內存,和使用一般的C+動態分配內存函數一樣了。 更改保護屬性更改已經提交的頁面的保護屬性,有時候會很有用處,假設你在訪問數據后,不想別的函數再訪問,或者出于防止指針亂指改變結構的目的,你可以更改數據
67、所處的頁面的屬性,讓別人無法訪問。VirtualProtect (PVOID 基地址,SIZE_T 大小,DWORD 新屬性,DWORD 舊屬性“基地址”是你想改變的頁面的地址,注意,不能跨區改變。C+程序:更改一頁的頁面屬性,改為只讀,看看還能不能訪問DWORD protect; iP0=8; &
68、#160; VirtualProtect(pV,4096,PAGE_READONLY,&protect; int * iP=(int*pV;iP1024=9;/可以訪問,因為在那一頁之外 /iP0=9;不可以訪問,只讀
69、; /還原保護屬性 VirtualProtect(pV,4096,PAGE_READWRITE,&protect; cout<<"初始值="< 可以訪問 清除物理存儲器內容清除頁面指的是,將頁面清零,
70、也就是說當作頁面沒有改變。假設數據存在物理內存中,系統沒有RAM頁面后,會將這個頁面暫時寫進虛擬內存頁文件中,這樣來回的倒騰系統會很慢;如果那一頁數據已經不需要的話,系統可以直接使用。當程序需要它那一頁時,系統會分配另一頁給它。VirtualAlloc (PVOID 開始地址,SIZE_T 大小,DWORD 類型,DWORD 保護屬性“大小”如果小于一個頁面的話,函數會執行失敗,因為系統使用四舍五入的方法;“類型”是MEM_RESET。有人說,為什么需要清除呢,釋放不就行了嗎?你要知道,釋放了后,程序就無法訪問了。現在只是因為不需要結構的內容了,順便提高
71、一下系統的性能;之后程序仍然需要訪問這個結構的。C+程序:清除1M的頁面:PVOID re=VirtualAlloc(pV,1024*1024,MEM_RESET,PAGE_READWRITE; if(re=NULL cout<<"清除失敗!"< 這時候,頁面可能還沒有被清零,因為如果系統沒有RAM請求的話,頁面內存保存不變的,為了看看被清零的效果,程序人為的請求大量頁面:C+程序:
72、VirtualAlloc(char*pV+100*1024*1024+4096,memStatus.dwAvailPhys+10000000,MEM_COMMIT,PAGE_READWRITE;/沒訪問之前是不給物理內存的。 char* pp=(char*pV+100*1024*1024+4096; &
73、#160; for(int i=0;i ppi='V'/逼他使用物理內存,而不使用頁文件 GlobalMemoryStatus(&memStatus;
74、 cout<<"內存初始狀態:"< cout<<"長度="< cout<<"內存繁忙程度="<
75、0; cout<<"總物理內存="< cout<<"可用物理內存="< cout<<"總頁文件="< &
76、#160; cout<<"可用頁文件="< cout<<"總進程空間="< cout<<"可用進程空間="&l
77、t; cout<<"清除后="< 結果如下: 當內存所剩無幾時,系統將剛清除的內存頁面分配出去,同時不會把頁面的內存寫到虛擬頁面文件中。可以看見,原先是8的值現在是0了。 虛擬內存的關鍵之處虛擬內存存在的優點是,需要的時候才真正分配內存。那么程序必須決定何時才提交內存。如果訪問沒有提交內存的數據結構,系統會產生訪問違規的錯誤。提交的最好方法是,當你程序需要訪問虛擬內存的數據結構時,假設它已經是分配內存的,然
78、后異常處理可能出現的錯誤。對于訪問違規的錯誤,就提交這個地址的內存。 釋放可以釋放整個保留的空間,或者只釋放分配的一些物理內存。釋放特定分配的物理內存:如果不想釋放所有空間,可以只釋放某些物理內存。“開始地址”是頁面的基地址,這個地址不一定是第一頁的地址,一個竅門是提供一頁中的某個地址就行了,因為系統會做頁邊界處理,取該頁的首地址;“大小”是頁面的要釋放的字節數;“類型”是MEM_DECOMMIT。C+程序:
79、; /只釋放物理內存 VirtualFree(int*pV+2000,50*1024*1024,MEM_DECOMMIT; int* a=(int*pV;
80、0; a10=2;/可以使用,沒有釋放這一頁 MEMORYSTATUS memStatusVirtual3; GlobalMemoryStatus(&memStatusVirtual3;
81、160; cout<<"物理內存釋放:"< cout<<"增加物理內存="< cout<<"增加可用頁文件="< cout<<"增加可用進程空間="< 結果如下: 可以看見,只釋放物理內存,沒有釋放進程的空間。 釋放整個保留的空間:VirtualFree (LPVOID 開始地址,SIZE_T 大小,DWORD 類
82、型“開始地址”一定是該區域的基地址;“大小”必須是0,因為只能釋放整個保留的空間;“類型”是MEM_RELEASE。C+程序:VirtualFree(pV,0,MEM_RELEASE; /a10=2;不能使用了,進程空間也釋放了 MEMORYSTATUS memStatusVirtual4;
83、 GlobalMemoryStatus(&memStatusVirtual4; cout<<"虛擬內存釋放:"< cout<<"增加物理內存="< cout<<"增加可用頁文件="< cout<<
84、;"增加可用進程空間="< 結果如下: 整個分配的進程區域被釋放了,包括所占的物理內存和頁文件。 何時釋放如果數組的元素大小是小于一個頁面4K的話,你需要記錄哪些空間不需要,哪些在一個頁面上,可以用一個元素一個Bit來記錄;另外,你可以創建一個線程定時檢測無用單元。 擴展地址AWEAWE是內存管理器功能的一套應用程序編程接口 (API
85、60;,它使程序能夠將物理內存保留為非分頁內存,然后將非分頁內存部分動態映射到程序的內存工作集。此過程使內存密集型程序(如大型數據庫系統)能夠為數據保留大量的物理內存,而不必交換分頁文件以供使用。相反,數據在工作集中進行交換,并且保留的內存超過 4 GB 范圍。對于物理內存小于2G進程空間時,它的作用是:不必要在物理內存和虛擬頁文件中交換。對于物理內存大于2G進程空間時,它的作用是:應用程序能夠訪問的物理內存大于2G,也就相當于進程空間超越了2G的范圍;同時具有上述優點。3GB當在boot.ini 上加上 /3GB 選項時,應用程序的進程空間增
86、加了1G,也就是說,你寫程序時,可以分配的空間又增大了1G,而不管物理內存是多少,反正有虛擬內存的頁文件,大不了慢點。PAE當在上加上 /PAE 選項時,操作系統可以支持大于4G的物理內存,否則,你加再多內存操作系統也是不認的,因為管理這么大的內存需要特殊處理。所以,你內存小于4G是沒有必要加這個選項的。注意,當要支持大于16G的物理內存時,不能使用/3G選項,因為,只有1G的系統空間是不能管理超過16G的內存的。AWE當在上加上 /AWE選項時,應用程序可以為自己保留物理內存,直接的使用物理內存而不通過頁文件,也不會被頁文件交換出去。當內存大于3G時,就顯得特別
87、有用。因為可以充分利用物理內存。當物理內存大于4G時,需要/PAE的支持。以下是一個的實例圖,是我機器上的: 要使用AWE,需要用戶具有Lock Pages in Memory權限,這個在控制面板中的本地計算機政策中設置。第一,分配進程虛擬空間:VirtualAlloc (PVOID 開始地址,SIZE_T 大小,DWORD 類型,DWORD 保護屬性“開始地址”可以是NULL,由系統分配進程空間;“類型”是MEM_RESERVE|MEM_PHYSICAL;“保護屬性”只能是PAGE_READWRITE。MEM_PHYS
88、ICAL指的是區域將受物理存儲器的支持。第二,你要計算出分配的頁面數目PageCount:利用本文第二節的GetSystemInfo可以計算出來。第三,分配物理內存頁面:AllocateUserPhysicalPages (HANDLE 進程句柄,SIZE_T 頁數,ULONG_PTR 頁面指針數組進程句柄可以用GetCurrentProcess(獲得;頁數是剛計算出來的頁數PageCount;頁面數組指針unsigned long* ArrayPageCount。系統會將分配結果存進這個數組。第四,將物理內存與虛擬空間進行映射:MapUserPhysicalPa
89、ges (PVOID 開始地址,SIZE_T 頁數,ULONG_PTR 頁面指針數組“開始地址”是第一步分配的空間;這樣的話,虛擬地址就可以使用了。如果“頁面指針數組”是NULL,則取消映射。第五,釋放物理頁面FreeUserPhysicalPages (HANDLE 進程句柄,SIZE_T 頁數,ULONG_PTR 頁面指針數組這個除了釋放物理頁面外,還會取消物理頁面的映射。第六,釋放進程空間VirtualFree (PVOID 開始地址,0,MEM_RELEASE C+程序:首先,在登錄用戶有了Lock Pag
90、es in Memory權限以后,還需要調用Windows API激活這個權限。BOOL VirtualMem:LoggedSetLockPagesPrivilege ( HANDLE hProcess,BOOL bEnable
91、 struct DWORD Count;/數組的個數
92、 LUID_AND_ATTRIBUTES Privilege 1; Info; HANDLE Token; /打開本進程的權限句柄
93、0; BOOL Result = OpenProcessToken ( hProcess, TOKEN_ADJUST_PRIVILEGES,
94、0; & Token; If (Result!= TRUE
95、; printf( "Cannot open process token.n" ; return FALSE;
96、0; /我們只改變一個屬性 Info.Count = 1;
97、60; /準備激活 if( bEnable Info.Privilege0.Attributes = SE_PRIVILEGE_ENABLED;
98、160; else Info.Privilege0.Attributes = 0; /根據權限名字找到
99、LGUID Result = LookupPrivilegeValue ( NULL, SE_LOCK_MEMORY_NAME,
100、0; &(Info.Privilege0.Luid; if( Result != TRUE
101、 printf( "Cannot get privilege for %s.n", SE_LOCK_MEMORY_NAME ;
102、 return FALSE; / 激活Lock Pages in Memory權限Result = AdjustTokenPrivileges ( To
103、ken, FALSE,(PTOKEN_PRIVILEGES &Info,0, NULL, NULL; if( Result != TRUE
104、; printf ("Cannot adjust token privileges (%un", GetLastError( ; return FALSE;
105、; else &
106、#160; if( GetLastError( != ERROR_SUCCESS printf ("Cannot enable the SE_LOCK_MEMORY_NAME privilege;
107、 " printf ("please check the local policy.n"
108、160; return FALSE;
109、160; CloseHandle( Token ; return
110、TRUE; 分配100M虛擬空間:PVOID pVirtual=VirtualAlloc(NULL,100*1024*1024,MEM_RESERVE|MEM_PHYSICAL,PAGE_READWRITE; if(pVirtual=NULL &
111、#160; cout<<"沒有那么大連續進程空間!"< MEMORYSTATUS memStatusVirtual5; GlobalMemoryStatus(&memStatusVirt
112、ual5; cout<<"虛擬內存分配:"< cout<<"減少物理內存="< cout<<"減少可用頁文件="< cout<<"減少可用進程空間="< 結果如下: 可以看見,只分配了進程空間,沒有分配物理內存。 分配物理內存:ULONG_PTR pages=(ULONG_PTR100*1024*1024/sysInfo.dwPageSize; ULONG_PTR *frameArray=new ULONG_PTRpages; /如果沒激活權限,是不能調用這個方法的,可以調用,但是返回FALSEBOOL flag=AllocateU
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 環境信號響應途徑-洞察及研究
- 福利院信息化建設-洞察闡釋
- 數據隱私保護教育對用戶隱私意識提升的作用研究-洞察闡釋
- 邢臺醫學高等專科學校《商品學》2023-2024學年第二學期期末試卷
- 動態頻譜共享Wi-Fi技術-洞察闡釋
- 去中心化智能合約共識算法-洞察闡釋
- 智慧養老中的物聯網智能設備與遠程監控的結合-洞察闡釋
- 個人發展與軟技能培訓企業制定與實施新質生產力項目商業計劃書
- 休閑車快速充電解決方案創新創業項目商業計劃書
- 劇場租賃與管理企業制定與實施新質生產力項目商業計劃書
- 德陽研學旅行課程的融合開發與實踐發展策略研究
- 病理學考試題庫
- 2025年全國普通高校招生全國統一考試數學試卷(新高考Ⅰ卷)含答案
- 事業單位考試(面試)試題附答案
- HYDRUS-2D3D學習手冊資料
- 數字化轉型項目管理試題及答案
- 2025年上海市七年級語文下學期期末考試復習(基礎知識+課內古詩文+課外文言文)
- 北京市海淀區2023-2024學年高二下學期期末考試英語試卷(含答案)
- 2025年中國電風扇行業市場現狀、進出口貿易、市場規模預測報告
- T/CSPSTC 75-2021微動探測技術規程
- 【語文】第23課《“蛟龍”探海》課件 2024-2025學年統編版語文七年級下冊
評論
0/150
提交評論