1. 程式人生 > 其它 >分段與分頁

分段與分頁

分段與分頁

一、分頁、分段的技術出現之前

  • 在分段這個技術還沒有出現之前,程式執行是需要從記憶體中分配出足夠多的連續的記憶體,然後把整個程式裝載進去

  • 如下圖所示,某個程式大小是10M,然後,就需要有連續的10M記憶體空間才能把這個程式裝載到記憶體裡面。如果無法找到連續的10M記憶體,就無法把這個程式裝載進記憶體裡面,程式也就無法得到執行

直接把整個程式裝載進記憶體的方式是有一定的問題的
①地址空間不隔離:舉個例子,假設我有兩個程式,一個是程式A,一個是程式B。程式A在記憶體中的地址假設是0x00000000~0x00000099,程式B在記憶體中的地址假設是0x00000100~x00000199。那麼假設你在程式A中,本來想操作地址0x00000050,不小心手殘操作了地址0x00000150,那麼,不好的事情或許會發生。你影響了程式A也就罷了,你把程式B也搞了一頓。
②程式執行時候的地址不確定:因為我們程式每次要執行的時候,都是需要裝載到記憶體中的,假設你在程式中寫死了要操作某個地址的記憶體,例如你要地址0x00000010。但是問題來了,你能夠保證你操作的地址0x00000010真的就是你原來想操作的那個位置嗎?很可能程式第一次裝載進記憶體的位置是0x00000000~0x00000099,而程式第二次執行的時候,這個程式裝載進記憶體的位置變成了0x00000200~0x00000299,而你操作的0x00000010地址壓根就不是屬於這個程式所佔有的記憶體
③記憶體使用率低下:
- 舉個例子,假設你寫了3個程式,其中程式A大小為10M,程式B為70M,程式C的大小為30M,但是你的計算機的記憶體總共有100M
- 這三個程式加起來有110M,顯然這三個程式是無法同時存在於記憶體中的
- 並且最多隻能夠同時執行兩個程式。可能是這樣的,程式A佔有的記憶體空間是0x00000000~0x00000009,程式B佔有的記憶體空間是0x00000010~0x00000079。假設這個時候程式C要執行該怎麼做?可以把其中的一個程式換出到磁碟上,然後再把程式C裝載到記憶體中。假設是把程式A換出,那麼程式C還是無法裝載進記憶體中,因為記憶體中空閒的連續區域有兩塊,一塊是原來程式A佔有的那10M,還有就是從0x00000080~0x00000099這20M,所以,30M的程式C無法裝載進記憶體中。那麼,唯一的辦法就是把程式B換出,保留程式A,但是,此時會有60M的記憶體無法利用起來,很浪費對吧
  • 對於上面的種種問題,分段的技術就出現了。為了實現分段的技術,需要引入虛擬地址空間的概念(見下)

二、分段技術的出現與虛擬地址空間

  • 分段:就是將一個程式分成程式碼段,資料段,堆疊段什麼的,每個段各自管理不同的資料

虛擬地址空間

  • 為了實現分段的這個技術,需要引入虛擬地址空間的概念

  • 從上面的圖片可以看出,程式被分成段之後,其在程式中操作的地址就是段地址(虛擬地址)

  • 簡單的說就是可以定址的一片空間。如果這個空間是虛擬的,我們就叫做虛擬地址空間;如果這個空間是真實存在的,我們就叫做實體地址空間。虛擬地址空間是可以任意的大的,因為是虛擬的。而實體地址空間是真實存在的,所以是有限的

虛擬地址空間到實體地址空間的對映

  • 分段技術把虛擬地址空間對映到了實體地址空間,並且你寫的程式操作的是虛擬地址

  • 假設,程式A的虛擬地址空間是0x00000100~0x00000200。此時,不僅需要一塊連續的實體記憶體來存放程式A,還需要把程式A的虛擬地址空間對映到(轉換為)實體地址空間。可能,程式A的虛擬地址空間從0x00000100~0x00000200對映到了實體地址空間0x00000000~0x00000100

分段技術解決了上面的問題①和問題②

  • 分段技術解決了問題①:

    • 在問題1中,假設程式A的虛擬地址空間是0x00000000~0x00000099,對映到的實體地址空間是0x00000600~0x00000699,程式B的虛擬地址空間是0x00000100~0x00000199,對映到的實體地址空間是0x00000300~0x00000399。假設你還是手殘,在程式A中操作了地址0x00000150,但是因為此時的地址0x00000150是虛擬的,而虛擬化的操作是在作業系統的掌控中的,所以,作業系統有能力判斷,這個虛擬地址0x00000150是有問題的,然後阻止後續的操作。所以,體現出了隔離性。(另一種體現隔離性的方式就是,操作同一個虛擬地址,實際上可能操作的是不同的實體地址)

    • (注意,實際上,很可能程式A和程式B的虛擬地址都是0x00000000~0x00000099。這裡的舉例只是為了方便理解。)

  • 分段技術解決了問題②:正是因為這種對映,使得程式無需關注實體地址是多少,只要虛擬地址沒有改變,那麼,程式就不會操作地址不當

  • 但是分段還有解決上面的問題③,於是分頁技術的出現解決了問題③

三、分頁技術的出現

  • 分段機制,對映的是一片連續的實體記憶體,所以問題③得不到解決。問題出在哪呢?就是完整和連續

分頁技術的大概原理

  • 分頁技術的出現就是為了解決上面的問題③的。分頁這個技術仍然是一種虛擬地址空間到實體地址空間對映的機制。但是,粒度更加的小了。單位不是整個程式,而是某個“頁”,一段虛擬地址空間組成的某一頁對映到一段實體地址空間組成的某一頁

  • 分頁這個技術,它的虛擬地址空間仍然是連續的,但是,每一頁對映後的實體地址就不一定是連續的了。正是因為有了分頁的概念,程式的換入換出就可以以頁為單位了。那麼,為什麼就可以只換出某一頁呢?實際上,不是為什麼可以換出某一頁,而是可以換出CPU還用不到的那些程式程式碼、資料。但是,把這些都換出到磁碟,萬一下次CPU就要使用這些程式碼和資料怎麼辦?又得把這些程式碼、資料裝載進記憶體。效能有影響對吧。所以,我們把換入換出的單位變小,變成了“頁”。(實際上,這利用了空間區域性性)

圖示說明如下圖所示:

  • 最左側的是使用者程式,程式在邏輯上仍然是分段的(程式碼段、棧區、堆區等),但是從物理儲存的角度來說,整個程式中被分為一頁一頁來進行儲存

  • 最右側的是記憶體,當用戶程式使用分頁技術之後,記憶體也被劃分為與程式頁面大小相同的塊

  • 中間是頁表,頁表的左側記錄的是程式的頁號,頁表右側記錄的是記憶體的快號;每一行的頁號與塊號存在對映關係,也就是說程式的某一頁是對映儲存在記憶體的某一塊上的。例如下圖所示,程式的第0頁儲存在記憶體的第2塊上,程式的第1頁儲存在記憶體的第3塊上......以此類推

  • 例如,下面是3個程式的對映情況,可以看到不同的程式它的記憶體被分為不同的頁,然後對映儲存在記憶體的不同塊中

頁面大小的選擇(選擇性閱讀)

  • 頁面大小是固定的,由你的機器和硬體所決定,不同的機器可能頁面大小不同

  • 頁面大小一般是2的冪,通常是512B~8KB

  • 頁面大小的區別:

    • 頁面尺寸小:記憶體碎片小,記憶體利用率高(因為頁面小,自己琢磨琢磨就好),但頁面數目多,使頁表過長,佔大量記憶體,管理開銷大

  • 頁面尺寸大:頁表端,記憶體利用率低且記憶體碎片化大(因為頁面大,自己琢磨琢磨就好),管理開銷小

頁面的地址結構(選擇性閱讀)

上圖給出一個頁的結構,如下圖所示:

  • 每個頁的結構如下,長度為32位,即每頁的大小為4KB

  • 0~11位:儲存位偏移(頁內地址),因此一個頁可以表示地址範圍為0~2^12

  • 12~31位:儲存的是頁號,地址空間最多允許有1M個頁,因此可以有2^20個頁面

所以當一個程式去定址的時候需要3個步驟:

  • 第一步:先通過查詢段,例如你訪問一個區域性變數,那麼就去程式的棧段中去找

  • 第二步:找到了棧這個段之後,再根據你這個變數的地址開始對4KB進行取餘操作,求出頁號,然後在找到你這個資料所儲存的頁地址

  • 第三步:當找到了指定的頁之後,因為地址對4KB取餘之後<=4KB,所以再根據取餘的結果在指定的頁中進行偏移,找到頁內偏移地址,最終訪問到實際地址

總結起來就是“段號+頁號+頁內偏移”

  • 總結:若給定一個邏輯地址空間中的地址為A,頁面大小為L,則有如下的公式

    • 頁號P=INT[A/L]

    • 頁內地址d=[A] mod L

    所以,分段和分頁的區別在於:粒度

四、分頁、分段的區別

  • 頁是資訊的物理單位,分頁是為實現離散分配方式,以消減記憶體的外零頭,提高記憶體的利用率。段則是資訊的邏輯單位,它含有一組其意義相對完整的資訊。分段的目的是為了能更好地滿足使用者的需要

  • 頁的大小固定,且由系統決定;而段的長度卻不固定,決定於使用者所編寫的程式

  • 分頁的地址空間是一維的,程式設計師只需利用一個記憶符,即可表示一個地址;而分段的作業地址空間是二維的,程式設計師在標識一個地址時,既需給出段名,又需給出段內地址

————————————————版權宣告:本文為CSDN博主「董哥的黑板報」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處連結及本宣告。原文連結:https://blog.csdn.net/qq_41453285/article/details/107827460