1. 程式人生 > >作業系統管理記憶體的機制,分段,分頁

作業系統管理記憶體的機制,分段,分頁

轉:http://blog.163.com/[email protected]/blog/static/1955478420113249937688/

一 早期的記憶體分配機制

        在早期的計算機中,要執行一個程式,會把這些程式全都裝入記憶體,程式都是直接執行在記憶體上的,也就是說程式中訪問的記憶體地址都是實際的實體記憶體地址。當計算機同時執行多個程式時,必須保證這些程式用到的記憶體總量要小於計算機實際實體記憶體的大小。那當程式同時執行多個程式時,作業系統是如何為這些程式分配記憶體的呢?下面通過例項來說明當時的記憶體分配方法:

      某臺計算機總的記憶體大小是128M,現在同時執行兩個程式A和B,A需佔用記憶體10M,B需佔用記憶體110。計算機在給程式分配記憶體時會採取這樣的方法:先將記憶體中的前10M分配給程式A,接著再從記憶體中剩餘的118M中劃分出110M分配給程式B。這種分配方法可以保證程式A和程式B都能執行,但是這種簡單的記憶體分配策略問題很多。

作業系統管理記憶體的機制——為什麼要設定虛擬記憶體? - 神之子 - 研究生了沒

圖一 早期的記憶體分配方法

       問題1:程序地址空間不隔離。由於程式都是直接訪問實體記憶體,所以惡意程式可以隨意修改別的程序的記憶體資料,以達到破壞的目的。有些非惡意的,但是有bug的程式也可能不小心修改了其它程式的記憶體資料,就會導致其它程式的執行出現異常。這種情況對使用者來說是無法容忍的,因為使用者希望使用計算機的時候,其中一個任務失敗了,至少不能影響其它的任務。

        問題2:記憶體使用效率低。在A和B都執行的情況下,如果使用者又運行了程式C,而程式C需要20M大小的記憶體才能執行,而此時系統只剩下8M的空間可供使用,所以此時系統必須在已執行的程式中選擇一個將該程式的資料暫時拷貝到硬碟上,釋放出部分空間來供程式C使用,然後再將程式C的資料全部裝入記憶體中執行。可以想象得到,在這個過程中,有大量的資料在裝入裝出,導致效率十分低下。

       問題3:程式執行的地址不確定。當記憶體中的剩餘空間可以滿足程式C的要求後,作業系統會在剩餘空間中隨機分配一段連續的20M大小的空間給程式C使用,因為是隨機分配的,所以程式執行的地址是不確定的。

二 分段

        為了解決上述問題,人們想到了一種變通的方法,就是增加一箇中間層,利用一種間接的地址訪問方法訪問實體記憶體。按照這種方法,程式中訪問的記憶體地址不再是實際的實體記憶體地址,而是一個虛擬地址,然後由作業系統將這個虛擬地址對映到適當的實體記憶體地址上。這樣,只要作業系統處理好虛擬地址到實體記憶體地址的對映,就可以保證不同的程式最終訪問的記憶體地址位於不同的區域,彼此沒有重疊,就可以達到記憶體地址空間隔離的效果。

       當建立一個程序時,作業系統會為該程序分配一個4GB大小的虛擬程序地址空間。之所以是4GB,是因為在32位的作業系統中,一個指標長度是4位元組,而4位元組指標的定址能力是從0x00000000~0xFFFFFFFF,最大值0xFFFFFFFF表示的即為4GB大小的容量。與虛擬地址空間相對的,還有一個實體地址空間,這個地址空間對應的是真實的實體記憶體。如果你的計算機上安裝了512M大小的記憶體,那麼這個實體地址空間表示的範圍是0x00000000~0x1FFFFFFF。當作業系統做虛擬地址到實體地址對映時,只能對映到這一範圍,作業系統也只會對映到這一範圍。當程序建立時,每個程序都會有一個自己的4GB虛擬地址空間。要注意的是這個4GB的地址空間是“虛擬”的,並不是真實存在的,而且每個程序只能訪問自己虛擬地址空間中的資料,無法訪問別的程序中的資料,通過這種方法實現了程序間的地址隔離。那是不是這4GB的虛擬地址空間應用程式可以隨意使用呢?很遺憾,在Windows系統下,這個虛擬地址空間被分成了4部分:NULL指標區、使用者區、64KB禁入區、核心區。應用程式能使用的只是使用者區而已,大約2GB左右(最大可以調整到3GB)。核心區為2GB,核心區儲存的是系統執行緒排程、記憶體管理、裝置驅動等資料,這部分資料供所有的程序共享,但應用程式是不能直接訪問的。

      人們之所以要建立一個虛擬地址空間,目的是為了解決程序地址空間隔離的問題。但程式要想執行,必須執行在真實的記憶體上,所以,必須在虛擬地址與實體地址間建立一種對映關係。這樣,通過對映機制,當程式訪問虛擬地址空間上的某個地址值時,就相當於訪問了實體地址空間中的另一個值。人們想到了一種分段(Sagmentation)的方法,它的思想是在虛擬地址空間和實體地址空間之間做一一對映。比如說虛擬地址空間中某個10M大小的空間對映到實體地址空間中某個10M大小的空間。這種思想理解起來並不難,作業系統保證不同程序的地址空間被對映到實體地址空間中不同的區域上,這樣每個程序最終訪問到的

       實體地址空間都是彼此分開的。通過這種方式,就實現了程序間的地址隔離。還是以例項說明,假設有兩個程序A和B,程序A所需記憶體大小為10M,其虛擬地址空間分佈在0x00000000到0x00A00000,程序B所需記憶體為100M,其虛擬地址空間分佈為0x00000000到0x06400000。那麼按照分段的對映方法,程序A在實體記憶體上對映區域為0x00100000到0x00B00000,,程序B在實體記憶體上對映區域為0x00C00000到0x07000000。於是程序A和程序B分別被對映到了不同的記憶體區間,彼此互不重疊,實現了地址隔離。從應用程式的角度看來,程序A的地址空間就是分佈在0x00000000到0x00A00000,在做開發時,開發人員只需訪問這段區間上的地址即可。應用程式並不關心程序A究竟被對映到實體記憶體的那塊區域上了,所以程式的執行地址也就是相當於說是確定的了。 圖二顯示的是分段方式的記憶體對映方法。

作業系統管理記憶體的機制——為什麼要設定虛擬記憶體? - 神之子 - 研究生了沒

圖二 分段方式的記憶體對映方法

       這種分段的對映方法雖然解決了上述中的問題一和問題三,但並沒能解決問題二,即記憶體的使用效率問題。在分段的對映方法中,每次換入換出記憶體的都是整個程式,這樣會造成大量的磁碟訪問操作,導致效率低下。所以這種對映方法還是稍顯粗糙,粒度比較大。實際上,程式的執行有區域性性特點,在某個時間段內,程式只是訪問程式的一小部分資料,也就是說,程式的大部分資料在一個時間段內都不會被用到。基於這種情況,人們想到了粒度更小的記憶體分割和對映方法,這種方法就是分頁(Paging)。

三 分頁

       分頁的基本方法是,將地址空間分成許多的頁。每頁的大小由CPU決定,然後由作業系統選擇頁的大小。目前Inter系列的CPU支援4KB或4MB的頁大小,而PC上目前都選擇使用4KB。按這種選擇,4GB虛擬地址空間共可以分成1048576個頁,512M的實體記憶體可以分為131072個頁。顯然虛擬空間的頁數要比物理空間的頁數多得多。

       在分段的方法中,每次程式執行時總是把程式全部裝入記憶體,而分頁的方法則有所不同。分頁的思想是程式執行時用到哪頁就為哪頁分配記憶體,沒用到的頁暫時保留在硬碟上。當用到這些頁時再在實體地址空間中為這些頁分配記憶體,然後建立虛擬地址空間中的頁和剛分配的實體記憶體頁間的對映。

        下面通過介紹一個可執行檔案的裝載過程來說明分頁機制的實現方法。一個可執行檔案(PE檔案)其實就是一些編譯連結好的資料和指令的集合,它也會被分成很多頁,在PE檔案執行的過程中,它往記憶體中裝載的單位就是頁。當一個PE檔案被執行時,作業系統會先為該程式建立一個4GB的程序虛擬地址空間。前面介紹過,虛擬地址空間只是一箇中間層而已,它的功能是利用一種對映機制將虛擬地址空間對映到實體地址空間,所以,建立4GB虛擬地址空間其實並不是要真的建立空間,只是要建立那種對映機制所需要的資料結構而已,這種資料結構就是頁目和頁表。

        當建立完虛擬地址空間所需要的資料結構後,程序開始讀取PE檔案的第一頁。在PE檔案的第一頁包含了PE檔案頭和段表等資訊,程序根據檔案頭和段表等資訊,將PE檔案中所有的段一一對映到虛擬地址空間中相應的頁(PE檔案中的段的長度都是頁長的整數倍)。這時PE檔案的真正指令和資料還沒有被裝入記憶體中,作業系統只是根據PE檔案的頭部等資訊建立了PE檔案和程序虛擬地址空間中頁的對映關係而已。當CPU要訪問程式中用到的某個虛擬地址時,當CPU發現該地址並沒有相相關聯的實體地址時,CPU認為該虛擬地址所在的頁面是個空頁面,CPU會認為這是個頁錯誤(Page Fault),CPU也就知道了作業系統還未給該PE頁面分配記憶體,CPU會將控制權交還給作業系統。作業系統於是為該PE頁面在物理空間中分配一個頁面,然後再將這個物理頁面與虛擬空間中的虛擬頁面對映起來,然後將控制權再還給程序,程序從剛才發生頁錯誤的位置重新開始執行。由於此時已為PE檔案的那個頁面分配了記憶體,所以就不會發生頁錯誤了。隨著程式的執行,頁錯誤會不斷地產生,作業系統也會為程序分配相應的物理頁面來滿足程序執行的需求。

       分頁方法的核心思想就是當可執行檔案執行到第x頁時,就為第x頁分配一個記憶體頁y,然後再將這個記憶體頁新增到程序虛擬地址空間的對映表中,這個對映表就相當於一個y=f(x)函式。應用程式通過這個對映表就可以訪問到x頁關聯的y頁了。

另外參考:http://blog.csdn.net/yang_yulei/article/details/24142743

相關推薦

Linux記憶體地址的分段機制(上)

在深入學習Linux核心原始碼之前,需要先對Linux執行的硬體基礎有個大概的認識,主要包括CPU中的暫存器和磁碟。 1.i386暫存器和系統指令 在Linux系統中使用的主要包括i386暫存器中的16位標誌暫存器,4個記憶體管理暫存器和4個控制暫存器及

作業系統管理記憶體機制分段

轉:http://blog.163.com/[email protected]/blog/static/1955478420113249937688/ 一 早期的記憶體分配機制         在早期的計算機中,要執行一個程式,會把這些程式全都裝入記憶體,程

操作系統筆記(十)內存管理分段和段

分段式內存管理 筆記 關系 代碼 保護 系統 長度 段頁式內存管理 bit 基本內存管理: 進程占用空間必須連續,導致外部碎片以及附加的compaction 整個進程的swap in 和 swap out十分耗時。 解決:分頁 ->內存空間不必連續,無外部碎片,

Linux記憶體管理解析(一) : 分段機制

背景 : 在此文章裡會從分頁分段機制去解析Linux記憶體管理系統如何工作的,由於Linux記憶體管理過於複雜而本人能力有限。會盡量將自己總結歸納的部分寫清晰。 從真實模式到保護模式的定址方式的不同 :    16位CPU的定址方式 : 在 8086 CPU 中,提供了兩類暫存器來進行定址,分別為段

儲存器管理——記憶體分配(分割槽

儲存器管理 連續分割槽兩種方式對比 固定分割槽 可變分割槽 分割槽記憶體大小 固定 可變 記憶體利用率 低 提高

分段記憶體管理

1.基本思想: 分頁系統能有效地提高記憶體的利用率,而分段系統能反映程式的邏輯結構,便於段的共享與保護,將分頁與分段兩種儲存方式結合起來,就形成了段頁式儲存管理方式。 在段頁式儲存管理系統中,作業的地址空間首先被分成若干個邏輯分段,每段都有自己的段號,然後再將每段分成若干個大小相等的頁。對於主存空間

作業系統分段機制

分段機制 分段,是指將程式所需要的記憶體空間大小的虛擬空間,通過對映機制對映到某個實體地址空間(對映的操作由硬體完成)。分段對映機制解決了之前作業系統存在的兩個問題:(1)地址空間沒有隔離。(2)程式

記憶體管理分段

記憶體管理 為什麼要有記憶體管理   多道程式作業系統中,程序的併發執行依賴於CPU排程。CPU能訪問的儲存器只有記憶體和(處理器中的)暫存器(機器指令可以用記憶體地址作為引數)。   暫存器價格昂貴且儲存空間小,因此程序執行的指令以及指令使用的資料主

Linux中的記憶體管理分段

前一段時間看了《深入理解Linux核心》對其中的記憶體管理部分花了不少時間,但是還是有很多問題不是很清楚,最近又花了一些時間複習了一下,在這裡記錄下自己的理解和對Linux中記憶體管理的一些看法和認識。 我比較喜歡搞清楚一個技術本身的發展歷程,簡而言之就是這個技術是怎麼發

Linux記憶體管理之一 分段

現代作業系統的記憶體管理機制有兩種:段式管理和頁式管理。段式記憶體管理,就是將記憶體分成段,每個段的起始地址就是段基地址。地址對映的時候,由邏輯地址加上段基地址而得到實體地址。純粹的段式記憶體管理的缺點很明顯,就是靈活性和效率比較差。首先是段的長度是可變的,這給記憶體的換入

Linux的記憶體定址——淺談分段機制

本文會以80x86架構,linux2.6為例,簡單介紹記憶體的分段和分頁機制。1. 三種記憶體地址關於記憶體地址,首先要了解它有三種,分別是邏輯地址、線性地址和實體地址。把邏輯地址轉換為線性地址是由一個叫做分段單元的硬體電路完成的。同樣地,還有一個叫做分頁單元的硬體電路負責把

嵌套頁面點擊刷新導致的界面問題

ces .com .html -1 oda () 問題 page blog 1.彈出框裏面數據,是後臺直接返回的一個頁面,點擊分頁整個頁面刷新,然後界面就亂了、、、、 點擊分頁後,界面如下 2.分頁代碼 <ul class="pagination"

ThinkPHP用異步來做玩轉類!

sse replace xpage private 替換 string 設置 nbsp urlencode 具體為什麽用異步來做分頁我就不多說了! 用異步來做分頁,主要還是看分頁類怎麽玩! 方便管理,還是把Ajax分頁作為一個工具來使用: 同樣新建工具類: 多次嘗試,最終

C# 發送http方法利用鍵值對 KeyValuePair發送命令日歷的開始和結束時間命令(POST)

!= 方法 call value face all 發送 keyvalue analysis 一個HTTP的類裏面: public static string HttpClientPost(string url, string taskIdx, string

LayerAjax請求

最近在研究layui,發現他的分頁標籤特別好用,所以小小研究了一下。 先來一個分頁後的效果圖看一下,是不是感覺特別精緻,話不多說,直接上程式碼!!!   下邊是程式碼檔案: 首先引入檔案: 注:layer框架是基於jquery的一個彈層框架,所以jquer

在 vue cli3 的專案中配置雙服務模擬 ajax 請求

最近安裝了下vue cli3版本,與 cli 2 相比,檔案少了,以前配置方法也不管用了。demo 中的大量的資料,需要做成 ajax 請求的方式來展示資料,因此,需要啟動兩個服務,一個用作前端請求,一個用作後端傳送。 雙服務的配置方法在 build / webpack.dev.conf.js 中寫入。

在 vue cli3 的項目中配置雙服務模擬 ajax 請求

new css listen -m dir ble col export code 最近安裝了下vue cli3版本,與 cli 2 相比,文件少了,以前配置方法也不管用了。demo 中的大量的數據,需要做成 ajax 請求的方式來展示數據,因此,需要啟動兩個服務,一個用作

Mybatis-plus多表關聯查詢多表查詢

學習plus真的覺得寫程式碼真的越來越舒服了。昨天開始接觸吧,只要學會了多表關聯查詢。plus就能隨意搭配使用了。 關於怎麼搭建的就自行了去研究了哦。這裡直接進入主題。 我用的是springboot+mybatis-plus。新專案我打算以後都是這樣了。   配置一個分頁外掛! im

十月專案小結(Recycler下拉重新整理上拉載入)

Recycler上拉分頁載入、下拉重新整理 該需求採用RecyclerView、SwipeRefreshLayout以及第三方外掛BRVAH結合使用方式完成,SwipeRefreshLayout完成下拉重新整理、BRVAH完成上拉分頁載入 build.gradle 配置說明

hibernate 一對多 或者多對多時候集合屬性怎麼 過濾? 一個人一百個訂單絕對要

1、集合過濾:      對於一個已經載入的Customer物件,假設對它的orders集合採用延遲載入機制,那麼當呼叫customer.getOrders().iterator()時,Hibernate就會初始化orders集合,然後到資料庫中去載