內存是現代計算機運行的中心(竟然不是CPU!)。內存有很大的一組字或字節組成,每一個字或字節都有地址。html
CPU根據程序計數器從內存中提取指令。CPU所能直接訪問的存儲器只有處理器內的寄存器和內存。一般,程序存儲在磁盤上,執行的時候,程序被調入內存。那麼CPU怎麼找到它們呢?程序員
一般,將指令與數據綁定到內存地址有如下幾種狀況:算法
1)編譯時,進程在內存中的駐留地址就已經肯定,生成的是絕對代碼數據結構
2)加載時,編譯器生成的是重定位代碼,綁定延遲到加載時才進行spa
3)執行時,絕大多數操做系統採用操作系統
1、背景指針
一、邏輯地址與物理地址htm
CPU所生成的地址稱爲邏輯地址,而內存單元對應的地址(即加載到內存地址寄存器的地址)稱爲物理地址。從邏輯地址到物理地址的映射由硬件設備(內存管理單元,MMU)完成。用戶只生成邏輯地址,這些地址在使用前必須映射到物理地址。用戶程序決不會看到真正的物理地址。對象
二、動態加載及DLLblog
若是一個進程的整個程序和數據必須處於物理內存中,那麼進程的大小會受物理內存大小所限制。可使用動態加載,子程序只在調用時才被加載。動態加載無須操做系統特別支持,這是程序員的工做。
除此而外,可使用DLL。DLL與動態加載不一樣,一般須要操做系統的幫助,由於DLL能夠被多個進程共用,只有操做系統能夠檢查其餘進程的內存空間。
DLL有版本的區別,不一樣版本的庫均可以裝入內存。
2、交換
進程須要在內存中以便執行,但進程能夠暫時從內存中換出(swap)到備份存儲上,當須要再次執行時再回到內存中。
交換有一些策略,好比基於優先級。
3、連續內存分配
內存一般分爲兩個區域:駐留操做系統 + 用戶進程。
一般須要將多個進程同時放在內存中,所以須要考慮如何爲輸入隊列中的進程分配內存空間。採用連續內存分配時,每一個進程位於一個連續的內存區域。
最簡單的內存分配方法之一就是將內存分爲多個固定大小的分區,每一個分區只能容納一個進程。這種方法如今已再也不使用。
有一種固定分區的升級版是可變分區,操做系統有一個表記錄內存的使用狀況。一開始,全部內存均可用於用戶進程,做爲一大塊可用內存,稱爲「孔」。當有新進程須要內存時,就爲它尋找一塊足夠大的孔。若是找到,從該孔中進行分配,孔剩餘部分能夠下次使用。
尋找孔的算法有
1)首次適應。找到第一塊足夠大的孔就中止。
2)最佳適應,全表掃描,找到最小且合適的一塊。
3)最差適應,全表掃描,找到最大且合適的一塊。
三種算法中,最差適應最差,首次適應比最佳適應快一點點。可是,後兩者產生的外部碎片問題(分區方法產生外部碎片,分頁產生內部碎片)也比最差適應要嚴重。解決之道是緊縮(靠,SQL SERVER也有碎片問題,也是靠索引重建或收縮來解決)。所謂的緊縮就是移動內存內容,以便將空閒空間合併成一塊。但並不是全部狀況都適用緊縮。若是內存物理地址重定位是靜態的,在彙編或裝入時進行,沒問題,但若是是在運行時才進行就開銷太大。
另外一種解決方案是容許物理地址爲非連續。這種方案就是如下的:分頁和分段。
4、分頁
分頁容許進程的物理地址空間非連續。
分頁避免了將不一樣大小的內存塊匹配到交換空間上這樣的麻煩。由於備份存儲也有與內存相關的碎片問題,而且訪問速度更慢,所以不適宜合併。而分頁是將物理內存劃分爲固定大小的塊,能夠避免外部碎片。分頁因爲其優越性爲絕大多數操做系統所採用。
分頁由硬件支持。不過,最新的趨勢是經過硬件和OS相配合,尤爲是在64位微處理器上。
一、基本方法
分頁方案中,物理內存劃分爲固定大小的的塊,稱爲幀(frame);與之對應,邏輯內存也分爲一樣大小的塊,稱爲頁。一樣,備份存儲也有一樣大小的塊。大小由硬件決定,一般爲2的冪,以方便將邏輯地址轉換爲頁號和頁偏移。
p:頁號
d:頁偏移量
f:幀號
由CPU生成的每一個地址分爲2部分:頁號(p)和頁偏移(d)。p做爲頁表的索引,頁表包含每頁所在物理內存的基地址,基地址 + 頁偏移 = 物理地址。如圖
採用分頁技術不會產生外部碎片,但可能又內部碎片。由於進程所要求的內存不必定是頁的整數倍。頁究竟取多大的值,這是個問題。
分頁的一個特色是用戶視角的內存和實際的物理內存分離。從用戶角度看,用戶程序將內存做爲一整塊來處理,而且整個內存只有它本身存在。但事實上,上面有各類各樣的進程,而且物理地址分佈多是不連續的。
這種差別,經過硬件進行映射轉換。而這一切,對用戶來講是透明的,但受操做系統控制。用戶程序不能越界訪問,沒法訪問其頁表規定以外的內存。
因爲操做系統管理物理內存,它必須清楚物理內存的分配細節,知道幀的使用狀況,可用數,總數,等等。這些信息一般保存在幀表的數據結構中。
二、硬件支持
操縱系統如何維護頁表?
絕大多數是爲每一個進程分配一個頁表,頁表指針與其餘寄存器一塊兒存入進程控制塊中。
頁表能夠用一組專用的寄存器來保存,這是效率最高的方法。但只適用於頁表不大的狀況。
若是頁表很是大,如1百萬個條目,就須要存放在內存,用頁表基寄存器指向頁表。改變基寄存器就能夠切換頁表,快得很。
不過由此而來的問題是,採用這種方案,訪問一個字節如今須要2次內存訪問,相對於原來速度減半。這種延遲是沒法忍受的。對這個問題的解決方案是採用硬件緩衝:轉換表緩衝區,TLB。TLB只維護頁表中的一小部分條目,邏輯地址轉換物理地址過程當中,先在TLB中查找,若是找到,那麼物理地址唾手可得;若是TLB中沒有,那麼使用置換算法,將相關條目置換進TLB,而後再獲得物理地址。
三、保護
分頁環境下,內存保護經過每一個幀的關聯保護位來實現。一般,這些位於頁表中。
這個位,定義一個頁是可讀寫仍是隻讀。
還能夠定義一個有效-無效位。當該位爲有效時,表示該頁在進程的邏輯地址空間內,是合法的頁,不然屬非法地址。一個進程不多會使用其全部的地址空間,而只使用一小部分。
四、共享頁
分頁的另外一個好處是能夠共享公共代碼。
5、頁表結構
一、層次頁表
對於一個進程,一個頁表已經能夠對應很多的條目,好比說,100萬條,那就是100萬個內存地址。若是還不夠,那麼頁表能夠再分層級,將頁表再分頁。原先的邏輯地址是
頁碼 + 頁偏移
,如今頁表分層後,變爲 頁碼 + 頁偏移 + 頁偏移
二、哈希頁表
處理超過32位地址空間的經常使用方法是使用哈希頁表。
哈希頁表的條目包括一個鏈表的元素,每一個元素有3個域:1)虛擬頁碼 2)物理幀號 3)指向鏈表中下一個元素的指針。其中虛擬頁碼做爲哈希值。(所謂虛擬頁碼,應該就是頁碼、頁號)
算法主要是憑頁碼獲得哈希值,在哈希表中得到對應條目,找到物理幀號。
三、反向頁表
爲避免頁表條目是否必須,都羅列在頁表中,從而形成頁表臃腫龐大的毛病,也能夠採用反向頁表。真正使用的幀纔在反向頁表中有一個條目。整個系統只有一張頁表,對每一個物理內存幀只有一個條目,條目包含對應邏輯內存頁的地址,及進程號等。主要的問題是內存共享有點麻煩。
6、分段
分頁的問題是用戶視角的內存和實際物理內存分離,邏輯內存須要映射到物理內存。
但對於咱們程序員來講,內存是一個集合,裏面有各類變量、對象,經過名字、指針來調用,而不關心它們到底位於什麼位置。
分段(segmentation)就是一種支持這種用戶視角的內存管理方案。邏輯地址空間由一組段組成。與分頁比較,其最大的不一樣是不固定大小。其他根據段號 + 偏移來得到物理地址,與分頁彷佛並沒有大的不一樣。
進程的地址空間被劃分爲若干個段,每一個段定義了一組邏輯信息。例程序段、數據段等。每一個段都從0開始編址,並採用一段連續的地址空間。所以,分段方案中,邏輯地址是二維的。
7、分頁與分段的主要區別
分頁和分段有許多類似之處,好比二者都不要求做業連續存放.但在概念上二者徹底不一樣,主要表如今如下幾個方面:
(1)頁是信息的物理單位,分頁是爲了實現非連續分配,以便解決內存碎片問題,或者說分頁是因爲系統管理的須要.段是信息的邏輯單位,它含有一組意義相對完整的信息,分段的目的是爲了更好地實現共享,知足用戶的須要.
(2)頁的大小固定,由系統肯定,將邏輯地址劃分爲頁號和頁內地址是由機器硬件實現的.而段的長度卻不固定,決定於用戶所編寫的程序,一般由編譯程序在對源程序進行編譯時根據信息的性質來劃分.
(3)分頁的做業地址空間是一維的.分段的地址空間是二維的.
打個比方,好比說你去聽課,帶了一個紙質筆記本作筆記。筆記本有100張紙,課程有語文、數學、英語三門,對於這個筆記本的使用,爲了便於之後複習方便,你能夠有兩種選擇。
第一種是,你從本子的第一張紙開始用,而且事先在本子上作劃分:第2張到第30張紙記語文筆記,第31到60張紙記數學筆記,第61到100張紙記英語筆記,最後在第一張紙作個列表,記錄着三門筆記各自的範圍。這就是分段管理,第一張紙叫段表。
第二種是,你從第二張紙開始作筆記,各類課的筆記是連在一塊兒的:第2張紙是數學,第3張是語文,第4張英語……最後呢,你在第一張紙作了一個目錄,記錄着語文筆記在第三、七、1四、15張紙……,數學筆記在第二、六、八、九、11……,英語筆記在第四、五、12……。這就是分頁管理,第一張紙叫頁表。你要複習哪一門課,就到頁表裏查尋相關的紙的編號,而後翻到那一頁去複習
四.段頁式存儲管理
1.基本思想:
分頁系統能有效地提升內存的利用率,而分段系統能反映程序的邏輯結構,便於段的共享與保護,將分頁與分段兩種存儲方式結合起來,就造成了段頁式存儲管理方式。
在段頁式存儲管理系統中,做業的地址空間首先被分紅若干個邏輯分段,每段都有本身的段號,而後再將每段分紅若干個大小相等的頁。對於主存空間也分紅大小相等的頁,主存的分配以頁爲單位。
參考文章:
http://blog.sina.com.cn/s/blog_4692ea0a0101j4ss.html