1. 程式人生 > >虛擬地址空間以及編譯模式

虛擬地址空間以及編譯模式

所謂虛擬地址空間,就是程式可以使用的虛擬地址的有效範圍。虛擬地址和實體地址的對映關係由作業系統決定,相應地,虛擬地址空間的大小也由作業系統決定,但還會受到編譯模式的影響。

這節我們先講解CPU,再講解編譯模式,讓大家瞭解編譯器是如何配合CPU來提高程式執行速度的。

CPU的資料處理能力

CPU是計算機的核心,決定了計算機的資料處理能力和定址能力,也即決定了計算機的效能。CPU一次(一個時鐘內)能處理的資料的大小由暫存器的位數和資料匯流排的寬度(也即有多少根資料匯流排)決定,我們通常所說的多少位的CPU,除了可以理解為暫存器的位數,也可以理解資料匯流排的寬度,通常情況下它們是相等的。

資料匯流排位於主機板之上,不在CPU中,也不由CPU決定,嚴格來講,這裡應該說CPU能夠支援的資料匯流排的最大根數,也即能夠支援的最大資料處理能力,為了表達方便,本文才使用“CPU的資料匯流排”這一說法。

資料匯流排和主頻都是CPU的重要指標:資料匯流排決定了CPU單次的資料處理能力,主頻決定了CPU單位時間內的資料處理次數,它們的乘積就是CPU單位時間內的資料處理量。

我們常常聽說,CPU主頻在計算機的發展過程中飛速提升,從最初的幾十 KHz,到後來的幾百 MHz,再到現在的 4GHz,終於因為矽晶體的物理特性很難再提升,只能向多核方向發展。在這個過程中,CPU的資料匯流排寬度也在成倍增長,從早期的8位、16位,到後來的32位,現在我們計算機大部分都在使用64位CPU。

需要注意的是,資料匯流排和地址匯流排不是一回事,資料匯流排用於在CPU和記憶體之間傳輸資料,地址匯流排用於在記憶體上定位資料,它們之間沒有必然的聯絡,寬度並不一定相等。實際情況是,地址匯流排的寬度往往隨著資料匯流排的寬度而增長,以訪問更大的記憶體。

1) 16位CPU

早期的CPU是16位的,一次能處理 16Bit(2個位元組)的資料。這個時候計算機產業還處在早期,個人電腦也沒有進入千家萬戶,也沒有提出虛擬地址的概念,程式還是直接執行在實體記憶體上,作業系統對記憶體的管理非常簡陋,程式設計師輕易就能編寫一個惡意程式去修改其他程式的記憶體。

學過彙編的同學應該知道,典型的16位處理器是 Intel 8086,它的資料匯流排有16根,地址匯流排有20根,定址能力為 2^20 = 1MB。

2) 32位CPU

隨著計算機產業的進步,出現了32位的CPU,一次能處理 32Bit(4個位元組)的資料。這個時候就提出了虛擬地址的概念,並被應用到CPU和作業系統中,由它們共同完成虛擬地址和實體地址的對映,這使得程式編寫更加容易,執行更加安全。

典型的32位處理器是 Intel 的 80386 和 Intel Pentium 4(奔騰4):80386 的資料匯流排和地址匯流排寬度都是32位,定址能力達4GB;Pentium 4的地址匯流排寬度是36位,理論定址能力達64GB。

3) 64位CPU

現代計算機都使用64位的CPU,它們一次能處理64Bit(8個位元組)的資料。典型的64位處理器是 Intel 的 Core i3、i5、i7 等,它們的地址匯流排寬度為 40~50 位左右。64位CPU的出現使個人電腦再次發生了質的飛躍。

實際支援的實體記憶體

CPU支援的實體記憶體只是理論上的資料,實際應用中還會受到作業系統的限制,例如,Win7  64位家庭版最大僅支援8GB或16GB的實體記憶體,Win7 64位專業版或企業版能夠支援到192GB的實體記憶體。

Windows Server 2003 資料中心版專為大型企業或國家機構而設計,可以處理海量資料,分為32位版和64位版,32位版最高支援512GB的實體記憶體,這顯然超出了32位CPU的定址能力,可以通過兩次定址來實現。

編譯模式

為了相容不同的平臺,現代編譯器大都提供兩種編譯模式:32位模式和64位模式。

32位編譯模式

在32位模式下,一個指標或地址佔用4個位元組的記憶體,共有32位,理論上能夠訪問的虛擬記憶體空間大小為 2^32 = 0X100000000 Bytes,即4GB,有效虛擬地址範圍是 0 ~ 0XFFFFFFFF。 

也就是說,對於32位的編譯模式,不管實際實體記憶體有多大,程式能夠訪問的有效虛擬地址空間的範圍就是0 ~ 0XFFFFFFFF,也即虛擬地址空間的大小是 4GB。換句話說,程式能夠使用的最大記憶體為 4GB,跟實體記憶體沒有關係。

如果程式需要的記憶體大於實體記憶體,或者記憶體中剩餘的空間不足以容納當前程式,那麼作業系統會將記憶體中暫時用不到的一部分資料寫入到磁碟,等需要的時候再讀取回來,這在《載入記憶體,讓程式執行起來》中已經講到。而我們的程式只管使用 4GB 的記憶體,不用關心硬體資源夠不夠。

如果實體記憶體大於 4GB,例如目前很多PC機都配備了8GB的記憶體,那麼程式也無能為力,它只能夠使用其中的 4GB。

64位編譯模式

在64位編譯模式下,一個指標或地址佔用8個位元組的記憶體,共有64位,理論上能夠訪問的虛擬記憶體空間大小為 2^64。這是一個很大的值,幾乎是無限的,就目前的技術來講,不但實體記憶體不可能達到這麼大,CPU的定址能力也沒有這麼大,實現64位長的虛擬地址只會增加系統的複雜度和地址轉換的成本,帶不來任何好處,所以 Windows 和 Linux 都對虛擬地址進行了限制,僅使用虛擬地址的低48位(6個位元組),總的虛擬地址空間大小為 2^48 = 256TB。

需要注意的是:

  • 32位的作業系統只能執行32位的程式(也即以32位模式編譯的程式),64位作業系統可以同時執行32位的程式(為了向前相容,保留已有的大量的32位應用程式)和64位的程式(也即以64位模式編譯的程式)。
  • 64位的CPU執行64位的程式才能發揮它的最大效能,執行32位的程式會白白浪費一部分資源。


目前計算機可以說已經進入了64位的時代,之所以還要提供32位編譯模式,是為了相容一些老的硬體平臺和作業系統,或者某些場合下32位的環境已經足夠,使用64位環境會增大成本,例如嵌入式系統、微控制器、工控等。

這裡所說的32位環境是指:32位的CPU + 32位的作業系統 + 32位的程式。

另外需要說明的是,32位環境擁有非常經典的設計,易於理解,適合教學,現有的很多資料都是以32位環境為基礎進行講解的。本教程也是如此,除非特別指明,否則都是針對32位環境。相比於32位環境,64位環境的設計思路並沒有發生質的變化,理解了32環境很容易向64位環境遷移。

開啟64位編譯模式

以 VS2010 為例,建立工程後預設是32位的,如下圖所示:


“Win32”表示32位編譯模式。如果要以64位的方式編譯,就需要新增編譯模式,如下圖所示:


選擇“配置管理器”,彈出如下的對話方塊:


在“活動解決方案平臺”下選擇“新建”,彈出下面的對話方塊:


在下拉選單中選擇“x64”,即可新增64位編譯模式。現在,我們就可以在兩種編譯模式之間進行切換了:


將下面的程式碼複製到原始檔中:

 
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. int a;
  4. int main(){
  5. int *p = &a;
  6. printf("%#X, %d\n", p, sizeof(int*));
  7.  
  8. system("pause");
  9. return 0;
  10. }

在 Win32 編譯模式下的結果:
0XB715C, 4

在 x64 編譯模式下的結果:
0X3FF39740, 8

 

 

轉自:https://blog.csdn.net/qq_28018113/article/details/73438094