1. 程式人生 > >計算機底層知識拾遺(八)理解實體記憶體管理

計算機底層知識拾遺(八)理解實體記憶體管理

記憶體管理是Linux核心最複雜的元件。記憶體管理包括虛擬記憶體機制和實體記憶體管理。這篇說說實體記憶體管理的一些要點。

實體記憶體地址空間和虛擬記憶體地址空間

說到虛擬記憶體的時候我們知道虛擬記憶體地址空間分為兩部分:核心地址空間和使用者程序地址空間。這兩個地址空間都使用虛擬地址,也就是說程式使用的都是虛擬地址。從虛擬地址對映到實際實體地址時有所區別:

1. 核心使用實體記憶體時可以直接通過虛擬地址和核心地址空間的起始值的偏移量來計算得到實際實體記憶體的地址

2. 程序使用實體記憶體必須通過頁表結構進行轉換

對應核心地址空間來說,

1. 如果核心虛擬地址空間 > 實體記憶體地址空間時, 那麼實體記憶體地址空間可以全部對映到核心虛擬地址空間。在目前64位機器的情況下基本都是這種情況,由於硬體的限制,可用的實體記憶體遠小於可用的核心虛擬地址空間

2. 如果核心虛擬地址空間 < 實體記憶體地址空間時,實體記憶體地址空間的一部分對映到核心虛擬地址空間,剩餘的實體記憶體地址空間被稱為高階記憶體(high memory),核心會採取額外的對映機制來訪問這些高階記憶體。這種情況在之前的32位機器上是常態,在32位機器下,核心地址空間和使用者程序地址空間的比例預設為1:3,也就是說4G的虛擬地址空間,核心地址空間佔1G,而可用的實體記憶體可達到4G,核心地址空間還必須預留一部分作為核心執行使用,所以可用的核心地址空間對實體記憶體地址空間的對映為896MB,剩餘的實體記憶體地址空間都是高階記憶體

對於64位機器來說,虛擬記憶體地址空間遠大於可用的實體記憶體地址空間,所以虛擬記憶體地址空間劃分成核心地址空間和使用者程序地址空間時就比32位機器的地址空間富裕很多,整個64位虛擬地址空間分為上下半部和中間禁用區三部分,可以看到虛擬地址的第0到46位都是任意設定的,而47位到63位對於核心地址空間來說都是0,對於使用者程序地址空間都是1。這種虛擬地址稱為規範的地址,其他的都是不規範的地址。所以在64位機器來說核心虛擬地址空間和使用者程序虛擬地址空間都是2的47次。


下圖是更細節的描述,核心的虛擬記憶體地址空間的起始部分是對物理內次地址空間的一致性對映,然後是vmalloc區域,然後是給核心使用的其他記憶體區域


之前說虛擬記憶體的時候已經說了頁表的結構,再來看一下頁表和一個虛擬地址的對映關係

1. 對於64位機器,4KB的頁大小來說,Offset表示該地址在頁內的偏移量,所以Offset 的長度=12, 2的12次方正好是4KB

2. PGD,PUD,PMD,PTE各位的長度都是9,也就是每級頁表的頁表項都是512個

3. 這樣總共64位的虛擬地址長度使用了48位,已經遠大於目前可用的實體記憶體地址空間


而頁表結構如下,每級頁表實際就是一個一個的陣列,陣列項的長度是64位的,上級頁表的頁表項存放著下級頁表的實體記憶體地址,而最後的PTE頁表項存放的就是實際實體記憶體頁的頁號。有了實體記憶體頁的頁號我們就可以找到對應實體記憶體頁。實體記憶體地址空間就是按照物理頁長度劃分的一個數組。PTE頁表項既然存放的是實體記憶體頁號,那麼肯定不需要64位長度,剩下的位可以用作標誌位來提供額外的功能,比如讀寫執行等許可權控制,是否是髒頁,是否被交換到了交換區等等。

實體記憶體的頁組織成了唯一一個數組,就是我們上面說的mem_map結構,而虛擬記憶體的頁卻採用了頁表結構,組織成了多級陣列結構,這樣的目的主要就是減少頁表的長度。虛擬記憶體當然也可以和實體記憶體一樣只使用一個唯一的陣列,但是虛擬記憶體地址空間有2的64次方這麼大,如果使用固定長度的陣列來表示,那麼有大量的陣列項是空的,因為實體記憶體沒這麼大。每個程序要維護自己的頁表,這樣虛擬記憶體也使用一個數組來表示,就造成了極大的記憶體浪費,因為儲存頁表是需要實體記憶體的。

採用了頁表這樣的多級陣列結構後,可以按需分配陣列,使用多少實體記憶體就分配多少虛擬地址空間的頁表項,這樣極大地壓縮了頁表長度,節省了實體記憶體。

關於頁表,需要記住的是使用者程序的虛擬地址是和這個地址對應的頁表陣列索引可以互相轉化計算。

實體記憶體資料結構

Linux要支援NUMA架構和非NUMA架構等多種硬體體系架構,在NUMA架構下,每個CPU獨享一個本地記憶體,在非NUMA架構比如SMP架構下,多個CPU共享一個實體記憶體,Linux對實體記憶體的管理必須要適用這多種架構。

所以Linux對實體記憶體的管理分為幾個層次

1. 最頂層是結點,在核心中是pg_data_t結構的例項

2. 每個結點又最多分為3個記憶體域,比如上面說的不可以直接對映的高階記憶體,可以直接對映的普通記憶體,已經給DMA用的記憶體域

3. 每個記憶體域都關聯了一個mem_map結構的陣列,陣列項都是page例項。page結構表示實體記憶體頁幀,是最重要的實體記憶體的表示結構。相當於把整個記憶體域的實體記憶體地址空間按頁大小(4KB-2MB)劃分成一個數組,這個陣列就是mem_map,陣列項就是page。得到了page結構,就得到了實體記憶體頁幀的位置,實體記憶體頁幀的狀態。

1. flags表示該實體記憶體頁幀的狀態

2. _count表示該頁被引用的計數器

3. private指標當在PagePrivate標誌下,用來指向該頁快取對應的底層buffer cache的buffer_head連結串列指標,當設定了PageSwapCache的時候,表示這個頁對應的頁交換區的位置資訊

4. mapping指標當作為檔案的頁快取時,指向該檔案inode對應的address_space地址空間。如果頁是匿名記憶體,即沒有後備檔案,那麼指向anon_vma匿名區域物件

5. virtual 指向這個實體記憶體地址對應的虛擬記憶體地址


實體記憶體分配

Linux核心在機器啟動時被載入到實體記憶體,核心映象在實體記憶體的儲存結構如下所示

1. 第一個物理頁幀4KB的空間是預留給BIOS使用的

2. 接下來的640KB區域預留未使用,原因是緊鄰該區域的後面一塊空間給載入ROM使用,ROM是不可寫的,所以如果這640KB給核心使用,必須保證核心小於640KB

3. Linux核心實際從1MB之後的連續記憶體開始,依次是核心程式碼,核心資料等

可以通過檢視/proc/iomem來檢視實體記憶體實際的分配情況,可以看到,核心程式碼是用第1MB實體地址開始的

當核心初始化完成之後,對實體記憶體的管理由夥伴系統承擔,下面看看夥伴系統的基本原理。

上面說了每個結點的記憶體分為3個域,域採用zone資料結構,包含一個free_area陣列。陣列的下標是階order。階是夥伴系統的一個重要術語,描述了記憶體分配的數量單元。記憶體塊的長度是2^order,階的範圍是0-MAX_ORDER。MAX_ORDER預設是11,也就是說一次分配可以請求的最大頁數是2^11 = 2048個頁

free_area結構包含了一個free_list連結串列。free_list是用於連線空閒頁的頁連結串列,頁連結串列包含大小相同的連續記憶體區。比如free_area[0]表示0階的空閒區域,它的頁連結串列包含的都是連續的空閒單頁。free_area[1]表示1階的空閒區域,它的頁連結串列包含的是連續的空閒雙頁


free_area陣列和free_list連結串列的組成如下圖所示。 free_list裡面大小相同的單元叫做夥伴,夥伴之間不需要連續,採用連結串列相聯。

系統當前夥伴系統資訊可以通過cat /proc/buddyinfo檢視


夥伴系統的特點是簡單高效,只使用了雙鏈表結構,它可以高效的分配連續的記憶體區域。對於使用者程序來說,實體記憶體碎片的問題影響還不大,因為使用者程序利用頁表來訪問實體記憶體,只要虛擬地址是連續的即可,vmalloc可以支援非連續的實體記憶體。但是對於核心來說,它直接映射了實體記憶體地址空間,如果實體記憶體碎片多,那麼影響核心的記憶體分配。比如下面這個結構,雖然只有4頁被分配了,但是對夥伴系統來說,它能分配的最大連續頁只能是8頁,因為分配的頁數都是2的冪,雖然有連續的15個頁,但是夥伴系統最大隻能分配8頁


為了解決記憶體碎片的問題,核心採用了反碎片的設計,試圖從最初開始儘可能防止碎片。

核心將已分配的頁分為三種類型

1. 不可移動頁 Unmovable。 核心中的已分配頁基本屬於這個型別,不能移動位置

2. 可回收頁 Reclaimable。 不能直接移動,但是可以刪除,其內容可以重新再生,比如對映到檔案的記憶體,可以重新讀取檔案內容來載入頁

3. 可移動頁 Movable,使用者空間的以分配頁基本屬於這個型別,因為使用者空間利用頁表訪問實體記憶體,可以通過複製頁到新的位置,然後更新頁表項來實現

反碎片的設計就是將相同移動性的頁分到一組。我們可以看到free_area裡面的free_list連結串列實際是按照移動性MIGRATE_TYPES分組的。

需要注意的是夥伴系統是核心用來分配大塊記憶體的,它只能分配2的冪的頁。slab分配器是核心用來分配細粒度的記憶體分配器。它們於C語言庫的malloc這種可以按照位元組大小來分配記憶體的分配器不同。夥伴系統分配器和slab分配器是最底層的核心級記憶體分配器,其他語言機的記憶體分配器都是基於它們來工作的

夥伴系統分配器的幾個API:

alloc_pages(mask, orders)分配2^order頁的實體記憶體並返回一個頁page結構,作為分配的記憶體的起始頁

get_zeroed_page(mask)分配一頁並返回page例項,頁對應的記憶體全部填充為0

__get_free_page(mask, order)返回分配記憶體塊的虛擬地址,而不是頁page例項。

free_page(struct page*)用於將page例項對應的實體記憶體頁返回給記憶體管理子系統,引數是page例項

__free_page(address)也是釋放記憶體給記憶體管理子系統,區別是傳遞引數是虛擬地址

關於記憶體分配系統,需要注意的是 所有的記憶體分配系統都是在初始化時預先獲得了一塊實體記憶體,在這個實體記憶體區域內再進行分配,釋放記憶體實際上就是把分配的記憶體返還給記憶體分配器

1. 比如核心的夥伴系統分配器,核心在初始化時會語言確定各個記憶體域的上下邊界,然後初始化各個記憶體域的各種資料結構,比如page例項,然後把這個記憶體域交給夥伴系統分配器。

2. 比如Java的記憶體管理,也是在Java程序啟動的時候指定了各個記憶體區域的大小,確定邊界,然後在Java程序啟動時就預先向核心申請了Java程序管理的大部分記憶體。Java的記憶體分配和垃圾回收都是在這塊預先分配的記憶體區域進行的。

vmalloc

核心使用vmalloc在虛擬記憶體地址空間分配連續的虛擬記憶體地址,這些連續的虛擬記憶體地址可以對映到不連續的實體記憶體頁,從而利用記憶體碎片。核心的虛擬記憶體地址空間有一塊專門的空間是給vmalloc使用的,每個vmalloc區域之後用空洞隔開,防止錯誤的虛擬地址引用。


每個用vmalloc函式建立的vmalloc區域物件都對應核心的一個vm_struct結構體

1. addr表示這個vmalloc區域的起始虛擬地址,size表示這個vmalloc區域的長度,這兩個引數就確定了一個vmalloc區域的邊界

2. flags標誌位表示了一組vmalloc區域的標誌

3. pages是一個page陣列,表示這個vmalloc區域對應的實際實體記憶體地址,可以是不連續的。nr_pages表示這個pages陣列的長度

4. next指標指向下一個vmalloc區域物件,所有的vmalloc區域物件組成一個單鏈表結構


vmalloc區域物件和實體記憶體的對映關係如下


slab分配器

夥伴系統分配器用來分配以頁為大小的大記憶體空間,核心同樣需要按位元組大小等細粒度分配記憶體空間的分配器,slab分配器就是這樣一個分配器

1. 分配細粒度的記憶體空間,是核心的kmallocAPI的底層實現。slab分配器對計算機快取記憶體影響小,原因是不會每次都分配頁,減少頁表的操作。而夥伴系統分配器每次都要更新頁表,而更新頁表會影響快取記憶體和TLB單元

2. 用作核心的快取,快取核心建立的資料結構的物件例項

slab分配器和夥伴系統的關係

相關推薦

計算機底層知識拾遺理解實體記憶體管理

記憶體管理是Linux核心最複雜的元件。記憶體管理包括虛擬記憶體機制和實體記憶體管理。這篇說說實體記憶體管理的一些要點。 實體記憶體地址空間和虛擬記憶體地址空間 說到虛擬記憶體的時候我們知道虛擬記憶體地址空間分為兩部分:核心地址空間和使用者程序地址空間。這兩個地址空間都使

計算機底層知識拾遺理解虛擬記憶體機制

這個系列會總結計算機,網路相關的一些重要的底層原理。很多底層原理大家上學的時候都學過,但是在學校的時候大部分的同學都是為了應付考試而學習,過幾天全忘了。隨著工作的時間越久,越體會到這些基礎知識的重要性。做技術和練武功一樣,當你到了一定的階段,也會遇到一個瓶頸,突破了你的眼界

計算機底層知識拾遺理解頁快取page cache和地址空間address_space

在這篇計算機底層知識拾遺(五)理解塊IO層 中講了塊快取buffer cache塊快取,這篇說說頁快取page cache以及相關的地址空間address_space的要點。 在Linux 2.4核心中塊快取buffer cache和頁快取page cache是並存的,表現

【SQL】- 基礎知識梳理 - 事務與鎖

隔離性 rep del 數據表 訪問 關系 snapshot 轉換 pro 事務的概念 事務:若幹條T-SQL指令組成的一個操作數據庫的最小執行單元,這個整體要麽全部成功,要麽全部失敗。(並發控制) 事務的四個屬性:原子性、一致性、隔離性、持久性。稱為事務的ACID特性。

計算機組成與設計—— 單週期處理器

處理器的設計步驟 分析指令系統,得出對資料通路的需求 為資料通路選擇合適的元件 連線元件,建立資料通路 分析每條指令的實現,以確定控制訊號 整合控制訊號,完成完整的資料通路   具體設計步驟 (一)分析指令系統 MIPS的所有指令是非常多的,我們只實現其簡化版,包

計算機組成與設計—— 單周期處理器

uri 處理器 lec zuche 輸入 style 我們 方式 gis 處理器的設計步驟 分析指令系統,得出對數據通路的需求 為數據通路選擇合適的組件 連接組件,建立數據通路 分析每條指令的實現,以確定控制信號 集成控制信號,完成完整的數據通路

C++ 重點知識梳理 -------- 實現函式和類

九、實現函式和類 9.1 char *strcpy(char *dst, const char *src); http://blog.csdn.net/yangquanhui1991/article/details/51804600 char *strcpy(char *

計算機作業系統知識彙總

作業系統 一、概述 1、基本特徵 (1)併發:併發是指巨集觀上在一段時間內能同時執行多個程式,而並行則指同一時刻能執行多個指令。作業系統通過引入程序和執行緒使得程式能夠併發執行; (2)共享:共享是指系統中的資源可以被多個併發程序共同使用。共享的方式有兩種:互斥

計算機底層原理雜談白話文

  簡單說一下寫這篇文章的緣由。首先這個不是教學型別的,是我Java實在學不下去了,因為好多計算機底層原理都不是很清楚,每次學新東西都由於想不明白底層原理困惑,所以下決心停止學習Java的新東西,開始搞明白底層。一開始搞的所謂的底層是“Java虛擬機器”,然後又C語言組合語言什麼的,其實是想圖快,儘快接近現在

Java基礎知識複習-- 遍歷ArrayList的三種方法

第一種遍歷 普通for迴圈 可以用size()和get()分別得到大小,和獲取指定位置的元素,結合for迴圈就可以遍歷出ArrayList的內容 第二種遍歷,使用迭代器 從最開始的位置判斷"下一個"位置是否有資料,如果有就通過next取出來,並且把指標向

計算機色彩知識調研:位深、Gamma值、標準色溫和Display P3

1. 位深度 計算機在記錄數字影象的顏色時,每種顏色需要用一定的位(bit)數來表示。“位”數越多,影象的色彩顯示就會越豐富。現在使用的圖片絕大部分都是8bit深的真彩圖,由於有RGB三個顏色通道,256 ^ 3 = 16777216,每個畫素可以表示出約1677萬種顏

java 基礎知識複習

(八)1. 當遍歷集合或陣列時,如果需要訪問集合或陣列的下標,那麼最好使用舊式的方式來實現迴圈或遍歷,而不要使用增強的for迴圈,因為它丟失了下標資訊。 2. Integer類有一個快取,它會快取介於-128~127之間的整數。 3. 可變引數:可變引數本質上就是一個數組,對

計算機色彩知識調研:色域

1. 什麼是色域 在計算機圖形學中,色域是指一個技術系統能夠產生的顏色的範圍總和,是顏色空間的某個完全的子集。 2. 人眼的色域 就目前而言,人眼的色域比大多數裝置的標準色域要寬廣得多。(其實也很好理解,人眼都看不到的顏色,裝置要顯示它幹嘛呢?) 所以,通常會用人

Objective-C 基礎知識:NSSet

集合 1、集合和陣列、字典類似,都只能儲存不同型別的物件。 集合中的物件具有唯一性,即同一物件在集合中儲存N次,集合只讀取一次物件,可通過NSCountedSet中的方法countForObject:獲取同一物件儲存的個數。 陣列可以儲存多次同一物件。 字典可以儲存多次同

Java基礎知識拾遺

日歷 映射 abcde spl 了解 找到 元素 next() 聲明 集合框架   SortedSet接口,聲明了以升序進行排序的行為。   Queue接口,聲明了隊列行為,隊列通常是先進先出的列表   Deque接口,擴展了Queue接口,聲明了雙端隊列的行為。雙端

Linux常用命令LVM邏輯卷管理

侯良金 linux lvm 邏輯卷 動態擴容 Linux常用命令(八)LVM邏輯卷管理一、LVM概述 LVM是Linux系統中對磁盤分區進行管理的一種邏輯機制,它是建立在硬盤和分區之上,文件系統之下的一個邏輯層,在建立文件系統時屏蔽了下層的磁盤分區布局,能夠在保持現有數據不變

spark調優-Apache Spark 記憶體管理詳解

Apache Spark 記憶體管理詳解 轉載於:https://www.ibm.com/developerworks/cn/analytics/library/ba-cn-apache-spark-memory-management/index.html Spark 作為一個基於記憶體的分散式計算引擎,

Oracle 自動共享記憶體管理ASMM與自動記憶體管理AMM

相關引數: MEMORY_MAX_TARGET:不可動態調整,代表記憶體(SGA+PGA)的最大值。 SQL>ALTER SYSTEM SET MEMORY_MAX_TARGET = 1000M SCOPE=SPFILE MEMORY_TARGET可被動

作業系統核心原理-5.記憶體管理:段式記憶體管理

一、分頁系統的缺點   分頁系統存在的一個無法容忍,同時也是分頁系統無法解決的一個缺點就是:一個程序只能佔有一個虛擬地址空間。在此種限制下,一個程式的大小至多隻能和虛擬空間一樣大,其所有內容都必須從這個共同的虛擬空間內分配。 二、分段管理系統 2.1 何為分段管理   分段管理就是將一個程式按照邏輯單

作業系統核心原理-5.記憶體管理:基本記憶體管理

  作業系統的兩個角色分別是魔術師和管理者,在管理者這個角色中,除了CPU之外,記憶體是作業系統要管理的另外一個重要資源。記憶體管理需要達到兩個目標:一是地址保護,即一個程式不能訪問另一個程式的地址空間。二是地址獨立,即程式發出的地址應該與物理主存地址無關。這兩個目標就是衡量一個記憶體管理系統是否完善的標準,