1. 程式人生 > >記憶體、虛擬記憶體的佈局

記憶體、虛擬記憶體的佈局

       記憶體是計算機中重要的部件之一,它是與CPU進行溝通的橋樑。計算機中所有程式的執行都是在記憶體中進行的,因此記憶體的效能對計算機的影響非常大。記憶體(Memory)也被稱為記憶體儲器,其作用是用於暫時存放CPU中的運算資料,以及與硬碟等外部儲存器交換的資料。只要計算機在執行中,CPU就會把需要運算的資料調到記憶體中進行運算,當運算完成後CPU再將結果傳送出來,記憶體的是否穩定執行決定了計算機的穩定性。再引入虛擬記憶體之前我們再說說程序與程式的主要區別:

 (1)程式是永存的;程序是暫時的,是程式在資料集上的一次執行,有建立有撤銷,存在是暫時的;

 (2)程式是靜態的觀念,程序是動態的觀念;

 (3)程序具有併發性,而程式沒有;

 (4)程序是競爭計算機資源的基本單位,程式不是。

 (5)程序和程式不是一一對應的: 一個程式可對應多個程序即多個程序可執行同一程式; 一個程序可以執行一個或幾個程式

       我們平常說的每個程序都有自己獨立的4G記憶體空間,但是實際上我們現在作用的個人計算機的記憶體水平最多也就是4G。那麼問題來了,一個程序佔據4G記憶體,一個程式往往分多個程序,首先是記憶體不夠用,其次如果只這樣的話,每個程序分開執行,這就存在執行等待的問題,甚至是程序阻塞。如此一來,計算機執行效率低下,顯然不可取。由此,引入了虛擬記憶體,顧名思義,作業系統是給每個程序分配了4G的虛擬記憶體,而不是記憶體。也就是說程式執行時作業系統先將相關的檔案和資料是先從磁碟上讀取,通過地址對映到虛擬記憶體上,記憶體通過和虛擬記憶體和實體記憶體間的對映關係獲取當下程序需要的檔案和資料。

        Intel 80386 微處理器的誕生之前,計算機記憶體採用的是實地址模式,之後才是我們現在所用的保護地址模式。它是 Intel公司80286及以後的x86(80386,80486和80586等)相容處理器(CPU)的一種操作模式。真實模式被特殊定義為20位地址記憶體可訪問空間上,它的容量是2的20次冪(1M)的可訪問記憶體空間(實體記憶體和BIOS-ROM),軟體可通過這些地址直接訪問BIOS程式和外圍硬體。真實模式下處理器沒有硬體級的記憶體保護概念和多道任務的工作模式。但是為了向下相容,所以80286及以後的x86系列相容處理器仍然是開機啟動時工作在真實模式下。1M 地址空間組成是由 16位的段地址和16位的段內偏移地址組成的。用公式表示為:實體地址

=左移4位的段地址+偏移地址。286處理器體系結構引入了地址保護模式的概念,處理器能夠對記憶體及一些其他外圍裝置做硬體級的保護設定(實質上就是遮蔽一些地址的訪問)。Intel 80386使用之後保護模式才真正使用,它具有許多特性設計為提高系統的多道任務系統的穩定性。例如記憶體的保護分頁機制硬體虛擬儲存的支援。最終的物理計算公式為:實體地址 = 左移 4 位的段地址 + 偏移地址。保護模式下存在著分段地址對映,首先由基地址+邏輯地址/偏移量得到線性地址,當操所繫統沒有開啟分頁機制時,這個線性地址就是實體地址,若開啟分頁機制,得到的是虛擬地址,必須要經過分頁地址對映才能得到我們想要的實體地址。

       在保護模式下,段是通過一系列被稱之為 “ 描述符表 ” 的表所定義的。段暫存器儲存的是指向這些表的指標。用於定義記憶體段的表有兩種:全域性描述符表(GDT) 和區域性描述符表 (LDT) 。GDT 是一個段描述符陣列,其中包含所有應用程式都可以使用的基本描述符。在真實模式中,段長是固定的 ( 為 64KB) ,而在保護模式中,段長是可變的,其最大可達 4GB 。LDT 也是段描述符的一個數組。與 GDT 不同, LDT 是一個段,其中存放的是區域性的、不需要全域性共享的段描述符。每一個作業系統都必須定義一個 GDT ,而每一個正在執行的任務都會有一個相應的 LDT 。

虛擬記憶體

接下來我們細說一下4G虛擬記憶體具體存放的是什麼,我們所寫的程式碼中的標頭檔案,定義的變數他們歸誰管。下面是我所畫的虛擬記憶體的佈局:

                                 

        虛擬記憶體的劃分比例為3:1,使用者可用的空間為3G,系統空間為1G。此圖的地址是從上往下一次增大,頂部的128M是保留區空間,使用者不能訪問,訪問系統就會報錯。.txt段存放的是指令,.data段存放的是初始化過且不為0的全域性變數和靜態全域性變數,.bss段存放的是未初始化的或者初始化為0的全域性變數和靜態全域性變數(.bss段實際上是不存在的,系統採用預留的方式以節省空間,因為它的值為0,給它分配空間沒有實際意義)。緊接著會預留一小部分空間放置越界訪問,然後是堆疊分割槽,堆區地址由低地址向高地址分配(堆區(Heap)用於動態記憶體的開闢,需要注意的是動態記憶體的開闢並不是使用者一次申請多少空間堆區就會減少多大空間,而是系統根據當前使用者使用的實時空間進行分配,以免讓開闢出來的空間處於空閒狀態。),棧區(Stack)地址由高地址向低地址分配空間,在堆區和棧區之間是共享庫的儲存區域。在棧之後是程式的命令列引數和環境變數的存放區域。從0xc000 0000到0xFFFF FFFF的系統區域是直接記憶體訪問區,常用部分割槽域和高階記憶體區域。