閑聊Linux記憶體管理(1)__Linux

來源:互聯網
上載者:User

今天還有時間,之前一直想抽時間來寫寫Linux核心原理相關的東西,關注點不在代碼,而在於內在的原理和機制,讓大家對Linux核心有個總體的感性認識,個人認為這很有必要,把看似複雜、深不可測的核心實現,用大家都能理解的方式,用講故事的方式,講給大家聽,如果有人聽後,有原來不過如此的感覺,那我的目的就達到了。

# 記憶體管理

從哪裡開始呢。還是從最基礎的記憶體管理開始吧。

記憶體管理是Linux核心中最基礎,也是相當重要的部分。理解相關原理,不管是對記憶體的理解,還是對大家寫使用者態代碼都很有協助。很多書上、很多文章都寫了相關內容,但個人總覺得內容太複雜,不是太容易理解,這裡想用我自己理解的簡單的方式來描述,希望能有所協助,按自己的思路,可能有點亂,見諒。 從記憶體配置開始

大家寫代碼時,應該都會分配記憶體,不同語言,層次不同,使用的介面不同,不管使用哪種方式,在Linux系統中,基本上都會調用到C庫的malloc介面,那就從malloc分配記憶體開始。

malloc就是用於分配一段記憶體,但這裡分配到的記憶體並非實體記憶體,而是虛擬記憶體,這裡沒有嚴格區分虛擬位址、線性地址之類的概念,只會給大家添負擔,也不深入講述實體記憶體和虛擬記憶體的概念,書上通常有大量的篇幅介紹,大家可以簡單這樣理解:

虛擬記憶體就是從進程的角度看,邏輯上的概念,並不實際存在;

實體記憶體就對應物理上記憶體條上的記憶體; 虛擬記憶體和實體記憶體有對應關係; 虛擬記憶體分配時,相應的實體記憶體還沒有分配;

既然虛擬記憶體並不實際存在,那麼分配來有何用處呢,如果要向其中寫資料,資料如何寫入呢。會寫到哪裡去呢。

當然,記憶體配置後就是拿來用的,如果不能用(比如寫資料),那就沒有意義了。前面說的虛擬記憶體和實體記憶體有對應關係,當分配虛擬記憶體時,相應的實體記憶體還沒有分配,這裡有幾個關鍵問題: 虛擬記憶體和實體記憶體的對應關係由誰來負責維護,如何對應。 實體記憶體何時分配。 虛擬記憶體到實體記憶體的映射

先來解答問題1。

由頁表來建立虛擬記憶體到實體記憶體之間的映射關係。 頁表是啥。

簡單看,頁表就是在記憶體中的一張表(不詳細介紹頁表的具體格式啥的,看書就可以了),可以簡單看做一張hash表,記錄的是虛擬位址和物理地址的對應關係,每個虛擬位址對應一個表項,通過這張表,就能將虛擬位址轉換為物理地址,也就能建立虛擬記憶體到實體記憶體的映射關係了。 誰用頁表。

頁表有了,那誰來用呢。不可能是應用程式自己用吧,我寫代碼時好像從來都沒見過頁表。

當然,使用者看到的只是虛擬位址(虛擬記憶體),其他的對使用者都是透明的~

CPU中有個硬體單元,叫MMU(記憶體管理單元),頁表就是給MMU硬體用的,MMU使用頁表進行虛擬位址到物理地址的映射。也就是說,地址映射是由硬體完成的,軟體(包括作業系統核心自身)都不管關心。

都說軟體不用關心了,那我們為嘛還需要講頁表。

軟體只是不用頁表而且,但頁表的建立和維護都是由軟體(作業系統核心)負責的,也就是說我們(軟體)建立虛擬記憶體和實體記憶體的映射關係,然後由硬體來自動進行地址映射(轉換),我們不需要關心具體的轉換過程。

前面說了,頁表是在記憶體中,而頁表是由軟體建立的,那MMU如果知道頁表到底在哪兒呢。

簡單說,需要我們(軟體)告訴它在哪兒,如何告訴。當然,寫寄存器。CPU上有特別的寄存器(CR3),向其中寫入頁表的地址,MMU就知道了,然後硬體自己使用即可,我們就不管了。 有多少張頁表。

看似一張頁表就能完成所有的地址映射了。

當然不行,如果是這樣,虛擬記憶體就沒有什麼必要存在了。

這裡又涉及新概念了:進程,這是作業系統中最基礎的概念,其實不“新”。

系統中,所有任務都是以進程方式啟動並執行,每個進程都有自己的獨立的虛擬位址空間,好像又說複雜了,簡單說,就是每個進程都有自己的虛擬記憶體,獨立代表,其他進程看不到自己的虛擬記憶體,那麼就意味著,每個進程都需要獨立的虛擬記憶體到實體記憶體的映射,就是說,每個進程都需要自己的頁表。

所以,系統中有多少進程,就有多少張頁表。 頁表建立

前面說了,頁表的建立和維護是由作業系統核心完成的,那何時建立頁表呢。

如前面所說,每個進程都需要自己的頁表,顯然,頁表需要在進程建立時建立。具體的建立過程和原理就不講了。 頁表的維護

如果維護頁表。

當然,進程自己維護,如果維護。

拿前面的例子說,malloc分配虛擬記憶體後,並沒有分配實體記憶體,也沒有建立映射關係,沒有修改頁表,那到底什麼時候,由誰來做映射。

答案是:“缺頁異常”。 缺頁異常

缺頁異常(page fault)又是另一個專業術語,表面上看好像不好理解。

簡單看,就是一個異常。什麼是異常。這又是硬體上的概念了,具體看看書

簡單說,就是硬體上的一種機制,當硬體檢測到某種“不對”時,主動觸發,然後會自動跳轉到例外處理常式處理。異常跟中斷類似,區別在於,中斷是非同步,由外設觸發;異常是同步的,由CPU自己觸發;好像又扯遠了。

缺頁異常就是一種特定的異常,觸發條件是:MMU檢測到頁表項(頁表中的項~)不存在。 何時觸發缺頁異常。

MMU何時會去檢測頁表項。

當CPU需要訪問某個虛擬位址時,比如向某個虛擬位址寫資料(memset),需要將虛擬位址轉換成物理地址,此時MMU就會自動去頁表中找相應的頁表項,如果發現此時相應的頁表項(也就是虛擬位址到物理地址的映射關係)還不存在,那麼就會自動從硬體層面觸發缺頁異常。

也就說,缺頁異常是硬體自己觸發的,條件是當需要訪問某個虛擬位址,而該虛擬位址還沒有相應的頁表項時。

典型的情境就是,當malloc之後,對相應的虛擬位址執行memset操作。 缺頁異常中幹嘛。

缺頁異常後,會跳轉到相應的例外處理常式處理,該例外處理常式是核心中提前註冊好的,其中要做的主要操作,就是:分配實體記憶體,然後修改相應進程的頁表,建立該實體記憶體和虛擬記憶體的映射關係(頁表項)。

當然,實際實現要複雜得多,這裡不詳細描述。 回頭看看

再來重頭捋一下記憶體配置過程: 使用者態程式使用malloc介面,分配虛擬位址。 使用者程式訪問該虛擬位址,比如memset。 硬體(MMU)需要將虛擬位址轉換為物理地址。 硬體讀取頁表。 硬體發現相應的頁表項不存在,硬體自動觸發缺頁異常。 硬體自動跳轉到page fault的處理常式(核心實現註冊好) 核心中的page fault處理常式執行,在其中分配實體記憶體,然後修改頁表(建立頁表項) 異常處理完畢,返回程式使用者態,繼續執行memset相應的操作。

至此,虛擬記憶體和實體記憶體都分配完成,並完成映射。

另一個角度看,如果malloc分配記憶體後,一直不使用,那就一直不會分配實體記憶體,這種記憶體配置策略叫延遲分配,有其相應的好處,自己理解一下~ 接下來。

本章,從記憶體配置的角度看了Linux核心中記憶體管理的關鍵原理,已經以盡量簡單的方式描述了,希望沒給大家帶來負擔~

Linux記憶體管理還涉及其他很多方面,如: 核心自身使用的記憶體(slab、vmalloc) 夥伴系統 進程地址空間管理

後面抽空慢慢講,但都希望能盡量簡單,希望大家一看就明白。


原文地址: http://happyseeker.github.io/kernel/2016/11/10/memory-management-in-kernel.html

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.