[OS] 可執(zhí)行文件的裝載

1. 虛擬內(nèi)存

在早期的計(jì)算機(jī)中,程序是直接運(yùn)行在物理內(nèi)存上的,程序在運(yùn)行時(shí)訪問的地址就是物理地址??墒?,當(dāng)計(jì)算機(jī)中同時(shí)運(yùn)行多個(gè)程序時(shí),就會(huì)有很多問題。

假設(shè)我們計(jì)算有128MB內(nèi)存,程序A需要10MB,程序B需要100MB,程序C需要20MB。如果我們需要同時(shí)運(yùn)行程序A和B,那么比較直接的做法是將內(nèi)存的前10MB分配給程序A,10MB~110MB分配給B。
但這樣做,地址空間不隔離,內(nèi)存使用效率低,程序運(yùn)行的地址不確定。

解決這個(gè)問題的辦法是增加中間層,使用虛擬地址。通過某些映射的方法,將虛擬地址轉(zhuǎn)換成實(shí)際的物理地址。

每個(gè)進(jìn)程都有自己獨(dú)立的虛擬地址空間,且每個(gè)進(jìn)程只能訪問自己的地址空間。

2. 分段

最開始人們使用的一種叫做分段的方法,把一段虛擬空間映射到某個(gè)物理地址空間。
比如程序A需要10MB內(nèi)存,我們首先假設(shè)虛擬地址空間為0x000000000x00A00000,然后從實(shí)際物理內(nèi)存中分配一個(gè)相同大小的物理空間0x001000000x00B00000,最后把這兩塊相同大小的地址空間一一映射。

但是分段的方法換入換出內(nèi)存的都是整個(gè)程序,會(huì)造成大量的磁盤操作,嚴(yán)重影響速度。

3. 分頁

程序的局部性原理:當(dāng)一個(gè)程序在運(yùn)行時(shí),在某個(gè)時(shí)間段內(nèi),它只是頻繁的用到一小部分?jǐn)?shù)據(jù)。

于是人們想到了分頁的方法。
基本思想是,把地址空間認(rèn)為的等分成固定大小的頁,由硬件決定支持多種大小的頁,操作系統(tǒng)選擇一個(gè)。
例如,如果虛擬空間有8頁,每頁大小由1KB,那么虛擬地址空間就是8KB。假設(shè)計(jì)算機(jī)有13條地址線,即擁有2^13的物理尋址能力,那么理論上物理空間可以多達(dá)8KB。假設(shè),只配備了6KB的內(nèi)存。

那么,我們就可以把常用的數(shù)據(jù)和代碼頁裝載到內(nèi)存中,把不常用的代碼和數(shù)據(jù)保存在磁盤里,當(dāng)需要的時(shí)候再把它從磁盤中讀取到內(nèi)存中即可。
我們把虛擬空間的頁叫做虛擬頁(Virtual Page),把物理內(nèi)存中的頁叫做物理頁(Physical Page),把磁盤中的頁叫做磁盤頁(Disk Page)

如果進(jìn)程需要的頁不在內(nèi)存中時(shí),就會(huì)觸發(fā)頁錯(cuò)誤(Page Fault),硬件會(huì)捕捉到這個(gè)消息,由操作系統(tǒng)接管,把所需要的磁盤頁,裝入內(nèi)存中,并建立虛擬內(nèi)存與物理內(nèi)存的對(duì)應(yīng)關(guān)系。

4. 覆蓋裝入

程序執(zhí)行時(shí)所需要的指令和數(shù)據(jù)必須在內(nèi)存中才能正常運(yùn)行。最簡(jiǎn)單的辦法就是將程序運(yùn)行所需要的指令和數(shù)據(jù)全都裝入內(nèi)存中。但很多情況下,程序所需的內(nèi)存數(shù)量大于物理內(nèi)存數(shù)量,而且相對(duì)于磁盤來說,內(nèi)存是昂貴的,所以人們想盡各種辦法,盡可能的有效利用內(nèi)存。

后來研究發(fā)現(xiàn),程序運(yùn)行時(shí)有局部性原理,于是可以將程序最常用的部分駐留在內(nèi)存中,而將一些不太常用的數(shù)據(jù)存放在磁盤里,即動(dòng)態(tài)裝入。

覆蓋裝入(Overlay)頁映射(Paging)是兩種很典型的動(dòng)態(tài)裝載方法。

覆蓋裝入在虛擬存儲(chǔ)發(fā)明之前使用比較廣泛,現(xiàn)在幾乎已經(jīng)被淘汰了。覆蓋裝入的方法把挖掘內(nèi)存潛力的任務(wù)交給了程序員,程序在編寫時(shí)必須手工分割成若干塊,然后編寫一個(gè)小的輔助代碼來管理這些模塊何時(shí)應(yīng)該駐留內(nèi)存,何時(shí)應(yīng)該被替換掉。這個(gè)小的輔助代碼就是所謂的覆蓋管理器(Overlay Manager)。
程序員需要手工將模塊按照它們之間的調(diào)用依賴關(guān)系組織成樹狀結(jié)構(gòu)。覆蓋管理器,保證某個(gè)模塊被調(diào)用時(shí),整個(gè)調(diào)用路徑上的模塊都在內(nèi)存中。

覆蓋裝入的速度比較慢,是典型的用時(shí)間換空間的方法。

5. 頁映射

與覆蓋裝入類似,頁映射也不是一下子就把程序的所有數(shù)據(jù)和指令都裝入內(nèi)存,而是將內(nèi)存和所有磁盤中的數(shù)據(jù)和指令按照頁(Page)為單位裝載和操作。

由于頁映射包含操縱系統(tǒng)對(duì)頁錯(cuò)誤的自動(dòng)處理,可執(zhí)行文件的裝載和執(zhí)行就簡(jiǎn)化了,
(1)創(chuàng)建一個(gè)具有獨(dú)立虛擬地址空間的進(jìn)程
實(shí)際上并沒有分配空間,而是創(chuàng)建一個(gè)頁映射函數(shù),將虛擬地址頁映射到物理地址頁。這些映射關(guān)系也可以等到后面程序發(fā)生頁錯(cuò)誤的時(shí)候再進(jìn)行設(shè)置。

(2)讀取可執(zhí)行文件頭,建立虛擬地址空間與可執(zhí)行文件的映射關(guān)系
這一步所作的是虛擬空間與可執(zhí)行文件的映射關(guān)系。當(dāng)程序執(zhí)行發(fā)生頁錯(cuò)誤時(shí),操作系統(tǒng)將從物理內(nèi)存中分配一個(gè)物理頁,然后將該“缺頁”從磁盤中讀取到內(nèi)存中,再設(shè)置缺頁的虛擬頁和物理頁的映射關(guān)系,這樣程序才得以正常運(yùn)行。
所以,當(dāng)操作系統(tǒng)捕獲到缺頁錯(cuò)誤時(shí),它必須知道程序當(dāng)前所需要的頁在可執(zhí)行文件中的哪一個(gè)位置,這就是虛擬空間與可執(zhí)行文件之間的映射關(guān)系。

與可執(zhí)行文件各個(gè)段對(duì)應(yīng)的,Linux中將虛擬空間劃分為了相應(yīng)的段,成為虛擬內(nèi)存區(qū)域(VMA),在Windows中叫做虛擬段(Virtual Section)
例如:代碼VMA,數(shù)據(jù)VMA,堆VMA,棧VMA

(3)將CPU的指令寄存器設(shè)置成可執(zhí)行文件的入口地址,啟動(dòng)運(yùn)行
操作系統(tǒng)通過設(shè)置CPU的指令寄存器將控制權(quán)轉(zhuǎn)交給進(jìn)程,由此進(jìn)程開始執(zhí)行,這個(gè)入口地址一般是代碼段VMA的起始地址。

注:
當(dāng)CPU打算執(zhí)行這個(gè)地址的指令的時(shí)候,發(fā)現(xiàn)此頁面是一個(gè)空白頁,于是它就認(rèn)為這是一個(gè)頁錯(cuò)誤,CPU將控制權(quán)交給操作系統(tǒng),操作系統(tǒng)有專門的頁錯(cuò)誤處理例程來處理這種情況,操作系統(tǒng)查找虛擬頁與可執(zhí)行文件頁之間的映射關(guān)系,計(jì)算出相應(yīng)頁面在可執(zhí)行文件中的偏移,然后在物理內(nèi)存中分配一個(gè)物理頁面,將虛擬頁與分配的物理頁建立映射,再把控制權(quán)返還給進(jìn)程,進(jìn)程從剛才頁錯(cuò)誤的位置重新開始執(zhí)行。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容