存儲的基本管理需求
重定位
重定位(Relocation):需要解決可執行文件中地址(指令和數據)和內存地址的對應。
一般有兩種比較常見的重定位方式:
- 靜態重定位(static relocation):當程序被裝入內存時,一次性實現邏輯地址到物理地址的轉換,以后不再轉換。
- 缺乏保護,可能會被其他程序非法訪問
- 運行時無法再次定位:無法移動、對換
- 動態重定位(Dynamic Relocation):在程序運行過程中要訪問內存時再進行地址變換
- 需要硬件支持
- 需要OS參與
重定位是一個比較有意思的話題,在操作系統和計算機組成原理,甚至編譯原理、匯編原理都會提到。簡單地說,就是把我們代碼中數據和指令的相對地址重新定位到實際內存地址,后面也會涉及到。
保護
即:未經許可,進程不能訪問其他進程的內存位置(范圍保護)
不過,在編譯時不可能檢查絕對地址,只能在運行時檢查。
原因很簡單,因為編譯的時候我們拿不到實際的絕對地址,只有在實際運行的時候才會有,一般編譯是得到機器代碼,鏈接是得到邏輯地址,裝入的時候才會確定實際的物理地址。
共享
即:允許多個進程訪問同一內存區域(代碼、數據)
舉一個很簡單的例子,絕大多數OS都有的剪貼板。當你復制了一份內容,你可以粘貼到微信,也可以粘貼到WPS甚至任何可以讀取它的進程。
邏輯組織
邏輯組織可以看成是一種線性組織,一般是程序員自己為了模塊化編程的需要組織起來的,所以稱之為“邏輯”組織。有以下幾個特點
- 有一些模塊可以修改,有些不能(類似int和const int)
- 不同模塊提供的保護不同(類似private和protected)
- 進程之間共享模塊(類似公共的函數/數據區)
- 分段存儲有助于邏輯組織(比如常見的代碼段、數據段等)
物理組織
物理組織的話至少就有兩個層次:主存和輔存。之前學習過組原的朋友都知道,主存一般指的內存,而輔存指的是外存。
如果OS的物理組織不好,程序、數據可用內存不足,搞不好就會卡死,甚至藍屏。
對于后端程序員來說由于內存不可見,編程的時候粗心可能就會導致服務器內存泄漏,最后宕機。
內存劃分
固定分區
等大分區:
內存被切成一個個相同大小的塊
- 程序太大,無合適分區(一份米飯男生不夠吃)
- 內存利用率不高(同樣一份米飯女生吃不完)
- 內碎片問題嚴重(每個分區利用不全,產生內部碎片)
不等分區:
小程序放入小分區,減少內碎片;大程序放入大分區,避免無法分配。
在算法實現上變得更加復雜,需要選擇合適的放置算法。此外,還有一些遺留問題:
- 活動進程的數目受限于系統
- 大量小進程無法有效利用空間
動態分區
按需分配,整體上提高了利用率
- 根據程序的運行的情況動態分區,每段內存按照程序需求的
- 分區與分區之間的外碎片的數量很多,雖然每一個占用空間不多,浪費也不少
→這時候就有了壓縮技術,把已分配的分區向一個方向移動,將外碎片壓縮。為了提高效率,還可以在分區的起始和截止地方存儲分區的信息
然后,讓我們來了解一下動態分區的放置算法
- 最佳適配算法
時間效率低下,由于要維護地址空間鏈表(B+樹),每次放置之后由于需要再次排序導致復雜度高。并且由于像41KB這種不好分配的內存,可能會導致碎片更碎。
- 首次適配算法
每次從頭開始尋找第一個足夠大的分區,前端重復搜索,后端空閑較多 - 循環首次適配算法
每次從上次放置位置往后掃描第一個滿足的內存分區,最大的分區容易被分割,需要壓縮來獲得新的大分區。
4. 最壞適應算法(worst-fit):找到最大的空閑分區
基本不留下小空閑分區,但較大的空閑分區不被保留。
5. 快速適應算法(quick-fit):為常用長度的空閑區建立單獨的空閑區鏈表
可快速找到所需的空閑區,但是歸還時合并復雜
看一個例子
如圖所示,我們此時需要16M的內存,first-fit從上往下找到第一個滿足的分區(指向22M的分區),best-fit找到最接近的分區(指向中間18M分區),而next-fit找到上次分配指針之后的第一個滿足的分區(指向36M分區)。
還有一種基于伙伴系統的分區算法,簡單了解即可
重定位
- 程序加載后實際(絕對)內存地址才確定
- 進程可能占據不同分區,即執行期間有不同絕對內存地址
首先了解一下幾個概念,學過匯編的應該都知道
- 邏輯地址:與當前數據分配到的物理內存地址無關的訪問地址
- 相對地址:表示為相對某個已知點的地址
- 物理或絕對地址:主存中的絕對地址或實際位置
- 地址映射:將用戶程序中的邏輯地址轉換為運行時由機器直接尋址的物理地址。
重定位圖示如下
這里的重定位就像是組原的基址變址尋址。圖中有一個基址寄存器,記錄了開始地址,還有界限寄存器記錄了結束地址。當進程加載或換入時設置寄存器值,程序傳入相對地址,OS通過“基址+相對地址=絕對地址”計算出實際地址同界限寄存器值比較,如果越界就發生中斷,反之去內存找數據。