1. 程式人生 > >我理解的Linux內存管理

我理解的Linux內存管理

bsp blog pan blank alloc 內容 討論 一個表 硬件檢測

眾所周知,內存管理是Linux內核中最基礎,也是相當重要的部分。理解相關原理,不管是對內存的理解,還是對大家寫用戶態代碼都很有幫助。很多書上、很多文章都寫了相關內容,但個人總覺得內容太復雜,不是太容易理解,這裏想用我自己理解的簡單的方式來描述,希望能有所幫助。本篇文章由圓柱模板博主原創,轉載需註明!

內存的分配

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

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

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

  • 物理內存就對應物理上內存條上的內存;

  • 虛擬內存和物理內存有對應關系;
  • 虛擬內存分配時,相應的物理內存還沒有分配;

虛擬內存到物理內存的映射

由頁表來建立虛擬內存到物理內存之間的映射關系。 頁表就是在內存中的一張表,可以簡單看做一張hash表,記錄的是虛擬地址和物理地址的對應關系,每個虛擬地址對應一個表項,通過這張表,就能將虛擬地址轉換為物理地址,也就能建立虛擬內存到物理內存的映射關系了。

頁表的使用

頁表有了,那誰來用呢?不可能是應用程序自己用吧,我寫代碼時好像從來都沒見過頁表? 當然,用戶看到的只是虛擬地址(虛擬內存),其他的對用戶都是透明的~ CPU中有個硬件單元,叫MMU(內存管理單元),頁表就是給MMU硬件用的,MMU使用頁表進行虛擬地址到物理地址的映射。也就是說,地址映射是由硬件完成的,軟件(包括操作系統內核自身)都不管關心。 都說軟件不用關心了,那我們為嘛還需要講頁表? 軟件只是不用頁表而且,但頁表的創建和維護都是由軟件(操作系統內核)負責的,也就是說我們(軟件)創建虛擬內存和物理內存的映射關系,然後由硬件來自動進行地址映射(轉換),我們不需要關心具體的轉換過程。 前面說了,頁表是在內存中,而頁表是由軟件創建的,那MMU如果知道頁表到底在哪兒呢? 簡單說,需要我們(軟件)告訴它在哪兒,如何告訴?當然,寫寄存器。CPU上有特別的寄存器(CR3),向其中寫入頁表的地址,MMU就知道了,然後硬件自己使用即可,我們就不管了。

頁表的數量問題

看似一張頁表就能完成所有的地址映射了? 當然不行,如果是這樣,虛擬內存就沒有什麽必要存在了。 這裏又涉及新概念了:進程,這是操作系統中最基礎的概念,其實不“新”。 系統中,所有任務都是以進程方式運行的,每個進程都有自己的獨立的虛擬地址空間,好像又說復雜了,簡單說,就是每個進程都有自己的虛擬內存,獨立代表,其他進程看不到自己的虛擬內存,那麽就意味著,每個進程都需要獨立的虛擬內存到物理內存的映射,就是說,每個進程都需要自己的頁表。 所以,系統中有多少進程,就有多少張頁表。

頁表創建

簡單來說,討論linux頁表就是討論linux進程的的頁表:linux頁表的創建與更新都包含於進程的創建與更新中。當前的linux內核采用的是寫時復制方法,在創建一個linux進程時,完全復制父進程的頁表,並且將父子進程的頁表均置為寫保護(即寫地址的時候會產生缺頁異常等)。那麽父子進程誰向地址空間寫數據時,產生缺頁異常,分配新的頁,並將兩個頁均置為可寫,按照這種方式父子進程的地址空間漸漸變得不同。 按照上面的分析, 只需要討論第一個進程頁表初始化,進程創建時頁表的拷貝,以及缺頁異常時頁表的更新即可。

什麽是缺頁異常

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

好了,時間也比較晚了,就寫到這,該睡覺了,明天又得早期了!明天晚上繼續寫寫這些理論的東西!學習需要堅持!

我理解的Linux內存管理