一、虛擬內存與物理內存
我們知道,每個應用程序都擁有自己獨立的4GB空間。例如,假設A進程在地址123處存儲了值10,而B進程在地址123處存儲了值20,這兩個進程互不影響。然而,這些值是真實存在的,并且存儲在物理內存中。如下圖所示:
根據上圖,我們可以區分虛擬內存和物理內存。如果我們修改了物理內存的值,那么會影響A進程或B進程。
當然,如果你學過內核驅動開發,就知道內核驅動讀寫正是這種機制。我也曾編寫過一個簡單的內核驅動讀寫程序,詳情請查看內核驅動目錄。
因此,虛擬內存是虛構的,只有在使用時才會映射到物理內存中。
二、物理內存的管理
物理內存是以4KB(即4096字節)的方式進行管理的,這一單位也稱為一頁。因此,在使用API時,我們經常會看到與頁相關的操作,這是因為內存是以頁為單位進行管理的。
如下圖所示:
進程A的值被放置在物理頁中。
傳統上,進程擁有4GB的地址空間,但實際上分為高2GB和低2GB。高2GB由內核使用,因此用戶只能使用低2GB。而低2GB中也有高低各64KB的部分是不可用的(如果學過內核,可以通過構造來使用)。
如下圖所示:
用戶模式可以使用的內存是橘黃色部分,但沒有對應的物理頁。只有當我們申請內存時,才會有對應的物理頁。
如果想查看三環程序使用的物理頁,可以通過雙機調試來調試我們的程序,使用Windbg進行操作:
- 首先使用命令!Process遍歷出我們程序的EXE地址。
- 使用dt EPROCESS遍歷出的地址,得到這個應用程序的EPROCESS結構。
- 得到EPROCESS結構中偏移11c(即成員VadRoot)的地址,使用!VAD地址(EPROCESS + 地址)可以得出這個EXE使用的內存物理頁。
如果你不會使用也沒關系,觀看下圖:
此圖說明了我們的線性地址從10開始到10結束。因為物理頁是以4KB存儲的,所以10代表的是1000,后面的大小是1000,因此下一個位置從20開始,即2000線性地址。
三、物理頁大小
物理頁的大小根據你的物理內存大小來設定。也就是說,你的物理內存有多大,就可以換算出物理頁的數量。我們可以通過任務管理器查看物理頁的總數。
例如,如下圖所示:
我們換算一下,1048048 / 4轉換為16進制就是可以有多少個物理頁。例如,我們的例子中有3FF7C個物理頁。
我們也可以使用Windbg通過dd命令查看,只需DD這個變量即可。
如果我們的物理頁超過了,那么操作系統還支持使用硬盤來作為物理內存。
具體設置如下:
計算機屬性 -> 高級系統設置 -> 高級 -> 性能設置 -> 高級 -> 虛擬內存更改。
這塊內存會在Windows上保存,文件名為pagefile.sys,通常是c盤的隱藏文件。我們可以通過everything搜索找到它。
三、操作系統可識別內存
我們可用的內存是我們計算出的物理頁大小加上虛擬內存的大小。然而,操作系統可識別的內存并不是這么大。
也就是說,即使我們增加了很多內存條,也不會有任何效果。
32位系統下最多能識別64GB內存,而WinXP只能識別4GB內存。具體知識需要學習Windows內核中的頁表(PTE、PDE)、頁目錄表等才能清楚,這里就不多說了,只需了解即可。