Windows 是多任務的操作系統, 一個任務就是一個應用(應用程序)、一個應用占一個進程; 在一個進程裡面, 又可以運行多個線程(所以就有了很多"多線程編程"的話題).
對 Win32 來講, 系統給每個進程 4GB 的地址空間:
低端 2GB($00000000 - $7FFFFFFF) 給用戶支配;
高端 2GB($80000000 - $FFFFFFFF) 留給系統使用.
文件或程序要調入內存才能工作, 先看看我們的內存到底有多大吧.
在系統盤根目錄下有個 pagefile.sys 文件, 這就是我們的 "虛擬內存"(虛擬內存是以文件的形式存在的).
把 pagefile.sys 叫做 "虛擬內存" 似乎不妥, 所謂的 "虛擬" 只是相對真實的物理內存(RAM)來講的; 很多書上的 "物理內存" 指的其實是: RAM + 虛擬內存, 也就是所有可用內存.
"虛擬內存" 在有些書上也被稱作 "頁文件" 、"頁面文件" 或 "交換文件". "虛擬內存" 的大小可以從 "控制面板" 裡設置, 默認是由系統自動管理的.
使用 "虛擬內存" 是系統的機制, 不管 RAM 有多大, 也應該使用 "虛擬內存".
RAM 大了, 系統就會少用 "虛擬內存", 從而提高速度; 但 RAM 也不是越大越好, 如果你真的放 4G 的內存條, 系統能夠識別並使用的也就是 3G 左右, 因為 Win32 只有 4G 的管理能力(尋址能力), 當然這在 Win64 下要另當別論.
所謂系統給每個程序 4G, 是給 4G 的 "虛擬的地址表", 絕不是真實的內存, 不然一個記事本、一個計算器就得需要 8G.
這個 "虛擬的地址表" 在有些書上叫 "虛地址表"、"頁映射表" 或 "虛內存地址", 也有叫 "虛擬內存地址", 很容易和 "虛擬內存" 的概念混淆.
這個 "虛擬的地址表" 上有 4G 個(4294967296 個)地址(0 - $FFFFFFFF), 雖然每個程序都有這樣一個表, 但它們並不會沖突, 就因為這些地址是虛擬的, 系統在需要的時候會把它們映射成具體的真實內存的地址. 這樣就阻斷了一個進程對另一個進程的訪問.
在 Win2000 以前的版本中, 用 GlobalAlloc 申請公用內存, 用 LocalAlloc 申請私有內存; 現在通過 "虛擬的地址表" 使用內存, 在進程中申請的內存都是私有的, 現在的 GlobalAlloc、LocalAlloc 沒有區別, 都是執行同樣的代碼.
如果需要跨進程的公用內存空間, 需要用 "內存映射" 等手段, 這需要再專題學習.
總結概念: 物理內存、虛擬內存、虛地址表.
函數 GlobalMemoryStatus 可以獲取它們的信息, 獲取後放在 TMemoryStatus 結構中.//TMemoryStatus 是 _MEMORYSTATUS 的重命名:
做個小程序看看內存情況:
_MEMORYSTATUS = record
dwLength: DWord; {結構長度}
dwMemoryLoad: DWord; {表示可用內存比例的一個整數, 100 表示內存都可用}
dwTotalPhys: DWord; {物理內存總數}
dwAvailPhys: DWord; {可用物理內存總數}
dwTotalPageFile: DWord; {虛擬內存總數}
dwAvailPageFile: DWord; {可用虛擬內存總數}
dwTotalVirtual: DWord; {虛地址表中的地址總數}
dwAvailVirtual: DWord; {虛地址表中可用的地址總數}
end;unit Unit1;
我這裡的運行效果圖:
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
m: TMemoryStatus;
const
num = 1024 * 1024;
begin
GlobalMemoryStatus(m);
Memo1.Clear;
with Memo1.Lines do begin
Add(Format('dwLength:' + #9 + '%d', [m.dwLength]));
Add(Format('dwMemoryLoad:' + #9 + '%d', [m.dwMemoryLoad]));
Add(Format('dwTotalPhys:' + #9 + '%d', [m.dwTotalPhys div num]));
Add(Format('dwAvailPhys:' + #9 + '%d', [m.dwAvailPhys div num]));
Add(Format('dwTotalPageFile:' + #9 + '%d', [m.dwTotalPageFile div num]));
Add(Format('dwAvailPageFile:' + #9 + '%d', [m.dwAvailPageFile div num]));
Add(Format('dwTotalVirtual:' + #9 + '%d', [m.dwTotalVirtual div num]));
Add(Format('dwAvailVirtual:' + #9 + '%d', [m.dwAvailVirtual div num]));
end;
end;
end.