邏輯地址和物理地址
程序的執(zhí)行過程:

- 源代碼
編譯成目標模塊,高級語言翻譯成機器語言 - 鏈接程序?qū)?code>目標模塊和它的
庫函數(shù)進行鏈接,形成完整的裝入模塊,裝入模塊從0開始編址,這稱為邏輯地址; - 裝入程序?qū)⒀b入模塊裝入內(nèi)存,裝入后形成
物理地址
邏輯地址:編程使用的地址,編譯的時候只關(guān)心程序的相對地址
物理地址:只有在放入內(nèi)存的時候,才需要使用物理地址,根據(jù)地址轉(zhuǎn)換方式可以從邏輯地址轉(zhuǎn)變?yōu)槲锢淼刂?/h6>
用戶在編程的時候只需要關(guān)系數(shù)據(jù)的邏輯地址,而這些邏輯上連續(xù)的數(shù)據(jù)在計算機內(nèi)存中的存放可能不是連續(xù)的,根據(jù)內(nèi)存管理方式的不同,數(shù)據(jù)的實際存放也會不同,地址轉(zhuǎn)換作為操作系統(tǒng)的職責(zé)之一,就是進行邏輯地址和物理地址的轉(zhuǎn)換,保證了程序員在寫代碼的時候只需要考慮數(shù)據(jù)的邏輯關(guān)系,而在操作系統(tǒng)底層這些數(shù)據(jù)是如何存放就不需要關(guān)系了,操作系統(tǒng)幫我們完成了;
目標模塊不同的裝入方式地址轉(zhuǎn)換的時機也會不同

程序的連接和裝入
一. 程序連接:
程序的連接是將編譯后的目標模塊和它的函數(shù)庫連接在一起;
1. 靜態(tài)連接:
在程序運行之前, 先將各目標模塊及它們所需 的庫函數(shù)連接成一個完整的 可執(zhí)行文件(裝入模塊), 之后不再拆開。
靜態(tài)連接的內(nèi)容:
- 空間與地址的分配。掃描所有的目標文件,合并相似段,收集當(dāng)中所有的符號信息。
- 符號解析與重定位。調(diào)整代碼位置。
靜態(tài)連接的特點:
- 簡單,浪費內(nèi)存,內(nèi)存中可能存在多個重復(fù)的函數(shù)庫,一個程序可能有多個模塊,每一個模塊的函數(shù)庫可能重復(fù)
- 不容易擴展,如果有新的目標模塊必須要重新編譯,鏈接
2. 動態(tài)連接:
在程序執(zhí) 行中需要該目標模塊時,才 對它進行鏈接。其優(yōu)點是便 于修改和更新,便于實現(xiàn)對 目標模塊的共享。
二. 程序的裝入
1. 絕對裝入:在編譯時就得到了絕對地址,按照編譯時得到的絕對地址裝入
- 只適用于單道程序環(huán)境
2. 靜態(tài)重定位裝入:根據(jù)內(nèi)存的當(dāng)前情況,將裝入模塊裝入內(nèi)存的合適位置,地址轉(zhuǎn)換通常在裝入時一次完成;
- 裝入時,必須為程序分配全部空間,分配后,進程不能在內(nèi)存中移動,不能再申請額外內(nèi)存;
3. 動態(tài)重定位裝入:程序可以在內(nèi)存中移動,裝入程序?qū)⒛繕四K裝入內(nèi)存后,不會直接將其邏輯地址轉(zhuǎn)換為物理地址,而是在程序真正運行時去進行地址轉(zhuǎn)換,地址轉(zhuǎn)換的過程通過一個重定位寄存器來完成
后續(xù)的內(nèi)存管理方式的基礎(chǔ),虛擬內(nèi)存的基礎(chǔ)
- 可以使用不連續(xù)的內(nèi)存
- 只需要將程序的部分代碼放入內(nèi)存就可以啟動程序
- 可以動態(tài)的調(diào)整程序的內(nèi)存大小
內(nèi)存保護
我們知道進程是不能直接訪問別的進程的資源的,進程也不能直接訪問內(nèi)存的資源,這是因為操作系統(tǒng)提供了一個內(nèi)存保護機制,一般內(nèi)存保護的實現(xiàn)方式有兩種:
1. 上下界寄存器:
CPU在執(zhí)行進程的指令去訪問一個地址時,會通過上下限寄存器判斷當(dāng)前訪問的這個地址是否越界


2. 界地址寄存器+重定位寄存器:
界地址寄存器存放最大的邏輯地址,重定位寄存器存放最小的物理地址,CPU在訪問內(nèi)存地址時,通過重定位寄存器判斷地址是否越界,如果沒有越界則結(jié)合重定位寄存器將邏輯地址轉(zhuǎn)換為物理地址訪問;

覆蓋與交換
內(nèi)存的擴充:
- 覆蓋
- 交換
- 虛擬內(nèi)存(后面細說)
覆蓋:
將內(nèi)存分成一個固定區(qū)和若干個覆蓋區(qū),將進程分成多個段,需要常駐在內(nèi)存的進程段放入固定區(qū),不常用的段放在覆蓋區(qū),需要時調(diào)入,不需要時調(diào)出;不能同時執(zhí)行的程序段共享一塊內(nèi)存區(qū)域
- 覆蓋區(qū)需要程序員指定,增加了編程負擔(dān),只用于早期的計算機系統(tǒng),現(xiàn)在已經(jīng)成為歷史
交換:
交換技術(shù)的思想:內(nèi)存中被阻塞展示得不到CPU運行的進程調(diào)出內(nèi)存至外存中,再將外存可以運行的進程調(diào)入內(nèi)存(中級調(diào)度)
- 將磁盤分成
文件區(qū)和對換區(qū),對換區(qū)存放被換出的進程數(shù)據(jù),對換區(qū)只占磁盤的很小部分,追求IO速度,一般采用的是連續(xù)分配方式;而文件區(qū)追求的是磁盤利用率,采用離散分配方式;
內(nèi)存分配方式:
連續(xù)內(nèi)存分配:
1. 單一連續(xù):
將內(nèi)存分成系統(tǒng)區(qū)和用戶區(qū),用戶區(qū)只能同時運行一個用戶進程;
- 無外部碎片,有內(nèi)部碎片,內(nèi)存利用率低
- 單用戶,單任務(wù)的操作系統(tǒng)
2. 固定連續(xù):
將用用戶空間的內(nèi)存分為多個固定大小的內(nèi)存,每一個可以小的內(nèi)存分區(qū)可以運行一個進程,分區(qū)可以是內(nèi)存相等也可以是內(nèi)存不相等的;
操作系統(tǒng)建立一張分區(qū)說明表用來對分區(qū)內(nèi)存進行管理
- 會產(chǎn)生內(nèi)部碎片
- 當(dāng)進程太大或者太小時就合適了,靈活性低
3. 動態(tài)連續(xù):
不會事先將用戶內(nèi)存劃分好,根據(jù)進程的大小,動態(tài)的劃分內(nèi)存;
- 會產(chǎn)生外部碎片,原本的大進程撤銷了再放入一個小進程,多出來的內(nèi)存就是外部碎片
非連續(xù)內(nèi)存分配:
1. 頁式內(nèi)存管理:
將用戶進程分成多個頁,將內(nèi)存分成多個塊,頁和塊大小相等,通過頁表一一對應(yīng);
地址轉(zhuǎn)換:
在分頁存儲管理中,邏輯地址由頁號和頁內(nèi)偏移量構(gòu)成;
- 頁表:操作系統(tǒng)為每一個進程都創(chuàng)建了一個頁表,頁表用來建立頁號與塊號的一一對應(yīng)關(guān)系;
- 頁表寄存器:操作系統(tǒng)會將進程的頁表信息(頁表地址,頁表長度)存放到PCB中,在切換到該進程時,會將PCB的頁表信息交給頁表寄存器,用于運行時的地址轉(zhuǎn)換;
- 頁表越界中斷判斷;
- 頁表寄存器結(jié)合頁號計算出當(dāng)前頁的頁表項,找出對應(yīng)的塊號
頁表項地址 = 頁表始址+頁表長度*頁號 - 找到對應(yīng)的塊始址,塊始址+偏移量就是物理地址

快表TLB:Translation Lookaside Buffer
一個比內(nèi)存訪問速度快很多的高速緩沖存儲器,用來緩存已經(jīng)進行過地址轉(zhuǎn)換的頁表項,用于加速地址轉(zhuǎn)換的過程,內(nèi)存中的頁表稱為慢表,具有快表的地址轉(zhuǎn)換過程如下
如果沒有快表,每一次地址轉(zhuǎn)換都需要訪問兩次內(nèi)存,一次查頁表項,一次查物理地址
二級頁表:
上面的頁表是一級頁表,一個進程的頁表必須連續(xù)的存放在內(nèi)存中,如果頁表過長,那么就會占用很大一段連續(xù)的內(nèi)存,這就違背了非連續(xù)存儲管理的思想,可以為一級頁表再創(chuàng)建一個頁表非連續(xù)的存放一級頁表的內(nèi)容;這個頁表稱為頁目錄表
二級頁表的邏輯地址結(jié)構(gòu):

二級頁表的地址轉(zhuǎn)換

首先通過一級頁號在頁目錄表中查找對應(yīng)的二級頁表的內(nèi)存,在通過二級頁號和二級頁表查找到對應(yīng)的實際內(nèi)存塊;
- 二級頁表解決了一級頁表過長占用大量的連續(xù)內(nèi)存的問題;
- 但是二級頁表需要三次訪問操作,一級頁表只需要兩次訪存,時間換空間;
2. 段式內(nèi)存管理:
將程序按照邏輯分成多個段,比如:主程序段,子程序段,數(shù)據(jù)段;將內(nèi)存也分成多個段,要求段內(nèi)的內(nèi)存連續(xù),段和段之間的內(nèi)存不連續(xù);操作系統(tǒng)系統(tǒng)通過段表建立進程段和內(nèi)存段之間的關(guān)聯(lián);
分段存儲的邏輯地址:

段表:

- 因為每一個段的長度是不一樣的,所以需要記錄每一個段的長度
地址轉(zhuǎn)換過程:
- 進程開始運行:從PCB將當(dāng)前進程的
段表始址,段表長度恢復(fù)給段表寄存器 - 界地址寄存器對段號進行越界中斷判斷
- 查找
段表項,段表始址+段表長*段號,得到段始址 - 段始址+段內(nèi)偏移量 = 物理地址
分頁和分段的對比:
- 分頁對用戶不可見,分段對用戶可見,用戶需要指定各個段
- 分段存儲有利于數(shù)據(jù)的共享,分頁內(nèi)存利用率高
- 分頁無外部碎片,分段有外部碎片
- 在不使用快表的情況下,分頁和分段都需要兩次訪存
3. 段頁式內(nèi)存管理:
結(jié)合分段和分頁方式的優(yōu)點,先將進程按照邏輯分成段,在將每一個段分成多個頁,將內(nèi)存分成多個塊,建立一張段表和多張頁表,保證頁和塊的一一對應(yīng);
段頁式管理的邏輯地址:

地址轉(zhuǎn)換過程:

- 段號越界中斷判斷
- 段表寄存器+段號找到段表項,即可找到對應(yīng)的頁表地址,頁表長度
- 頁號*頁表長度+頁表始址得到塊號
- 塊號+頁內(nèi)偏移量 = 物理地址
虛擬內(nèi)存:
傳統(tǒng)內(nèi)存分配方式的缺點:
- 需要一次性將進程全部裝入內(nèi)存,這樣會導(dǎo)致兩個問題:
- 當(dāng)進程過大無法裝入內(nèi)存運行
- 內(nèi)存的利用率非常的低
局部性原理:
- 時間局部性:當(dāng)一條指令被執(zhí)行后,在一段時間內(nèi),這條指令很可能再次被執(zhí)行,當(dāng)訪問了一個數(shù)據(jù)后,一段時間內(nèi)這個數(shù)據(jù)很可能再次被訪問;
- 空間局部性:一旦訪問了某一塊內(nèi)存,這個塊內(nèi)存附近的內(nèi)存也很大可能被訪問;
CPU的高速緩存就是基于局部性原理思想實現(xiàn)的
虛擬內(nèi)存:
基于局部性原理,我們在裝入進程到內(nèi)存的時候可以只將進程的啟動那部分代碼裝入內(nèi)存,就可以啟動進程,操作系統(tǒng)提供請求調(diào)頁和頁面置換功能;
- 請求調(diào)頁:當(dāng)進程在運行過程中需要使用外存的數(shù)據(jù)時,系統(tǒng)會將外存的頁調(diào)入到內(nèi)存中
- 頁面置換:當(dāng)內(nèi)存不足時,需要通過頁面置換算法選擇暫時不用的頁放到外存;
請求分頁存儲管理方式(分頁+虛擬內(nèi)存):
-
頁表:
缺頁中斷機制:
當(dāng)訪問一個頁時,會通過頁表的狀態(tài)位判斷當(dāng)前這個頁是否在內(nèi)存中,如果不在,會觸發(fā)一個缺頁中斷,內(nèi)核會阻塞當(dāng)前進程,執(zhí)行IO操作,將外存的頁調(diào)入到內(nèi)存,如果內(nèi)存不夠,會通過頁面置換算法置換出一個頁;
地址轉(zhuǎn)換過程:

整體的地址轉(zhuǎn)換和分頁存儲差不多,說一下不同的地方:
- 當(dāng)找到對應(yīng)的頁表項時會判斷當(dāng)前頁是否在內(nèi)存中,如果不在,觸發(fā)缺頁中斷,內(nèi)核會從外存進行IO操作,將頁從外存調(diào)入內(nèi)存,如果內(nèi)存不夠,還會進行頁面置換
頁面置換算法:
另一篇文章有詳述
- 最佳置換 :
- 先進先出
- LRU
- 時鐘算法
- 改進的時鐘算法
