linux內核內存slab,夥伴系統,內存碎片,內存耗盡(OOM)殺手,內存資源控制器memcg,KASAN學習筆記【轉】

轉自:https://blog.csdn.net/u010936265/article/details/108330347?spm=1001.2101.3001.6650.6&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-6.no_search_link

目錄

1 基礎知識

1.1 頁

1.2 頁表

1.3 UMA(一致性訪問) / NUMA(非一致性訪問)

1.4 高端內存和低端內存

1.5 內存模型

2 物理內存的管理

2.1 物理內存的組織:節點和管理區(內存域)簡介

2.1.1 簡介

2.1.2 備用區域列表 / 區域水線 / 內存域水印

2.1.3 相關函數

2.2 夥伴系統

2.2.1 簡介

2.2.2 夥伴系統實現原理

2.2.3 /proc/buddyinfo 中獲得夥伴系統的當前信息

3 slab 分配器

3.1 slab簡介

3.2 常用函數

3.3 /proc/slabinfo

3.4 /sys/kernel/slab/

3.5 slabtop 命令

3.6 注意點

4 vmalloc()和 kmalloc()以及它們之間的區別

4.1 vmalloc() / vfree()

4.1.1 簡介

4.1.2 注意點

4.2 kmalloc() / kfree() / kzalloc()

4.2.1 簡介

4.2.2 注意點

4.2.3 kmalloc(size, flags)接口中 flags 參數的說明

4.x vmalloc()和 kmalloc()的區別

5 __get_free_pages() / alloc_pages_node()

5.1 簡介

5.2 常用函數

6 分配函數的選擇

7 避免內存碎片(反碎片)

7.1 簡介

7.2 反碎片的技術

7.3 虛擬可移動區域

7.3.1 簡介

7.3.2 使用方法

7.4 根據可移動性分組

7.5 內存碎片整理(memory compaction)

7.5.1 簡介

7.5.2 使用方法

8 內存耗盡殺手

8.1 簡介

8.2 使用方法

8.3 內存耗盡殺手計算進程的壞蛋分數

9 內存資源控制器 / 控制組(cgroup) / 內存控制組(memcg)

9.1 簡介

9.2 控制組版本 1 的內存資源控制器的配置方法

10 內存錯誤檢測工具 KASAN

10.1 簡介

10.2 對編譯器的要求 和 對內核代碼版本的要求

10.3 使用方法

11 在系統引導時獲取緩衝區(bootmem分配器)

目錄

1 基礎知識

1.1 頁

1.2 頁表

1.3 UMA(一致性訪問) / NUMA(非一致性訪問)

1.4 高端內存和低端內存

1.5 內存模型

2 物理內存的管理

2.1 物理內存的組織:節點和管理區(內存域)簡介

2.1.1 簡介

2.1.2 相關函數

2.2 夥伴系統

2.2.1 簡介

2.2.2 夥伴系統實現原理

2.2.3 /proc/buddyinfo 中獲得夥伴系統的當前信息

3 slab 分配器

3.1 slab簡介

3.2 常用函數

3.3 /proc/slabinfo

3.4 /sys/kernel/slab/

3.5 slabtop 命令

3.6 注意點

4 vmalloc()和 kmalloc()以及它們之間的區別

4.1 vmalloc() / vfree()

4.1.1 簡介

4.1.2 注意點

4.2 kmalloc() / kfree() / kzalloc()

4.2.1 簡介

4.2.2 注意點

4.2.3 kmalloc(size, flags)接口中 flags 參數的說明

4.x vmalloc()和 kmalloc()的區別

5 __get_free_pages() / alloc_pages_node()

5.1 簡介

5.2 常用函數

6 分配函數的選擇

7 在系統引導時獲取緩衝區(bootmem分配器)

1 基礎知識
1.1 頁
物理地址被分爲離散的單元,稱之爲頁。
系統內部許多對內存的操作都是基於單個頁的。每個頁的大小隨體系架構不同而不同,但是目前大多數系統都使用每頁 4096 個字節。常量 PAGE_SIZE 給出了在任何指定體系架構下的頁大小。

仔細觀察內存地址,無論是虛擬的還是物理的,它們都被分爲頁號和一個頁內的偏移量。舉個例子,如果使用頁大小爲 4096 個字節,那麼最後的 12 位是偏移量,而剩餘的高位則指定了頁號。

如果忽略了地址偏移量,並將除去偏移量的剩餘位移到右端,稱該結構爲頁幀數。移動位以在頁幀數和地址間進行
轉換是一個常用操作;宏 PAGE_SHIFT 將告訴程序員,必須移動多少位才能完成這個轉換。

《LINUX 設備驅動程序》(第三版)P410

1.2 頁表
把線性地址映射到物理地址的數據結構稱爲頁表(page table)。頁表存放在主存中,並在啓用分頁單元之前必須由內核對頁表進行適當的初始化。 《深入理解 LINUX 內核》P51


用來將虛擬地址空間映射到物理地址空間的數據結構稱爲頁表。 《深入 LINUX 內核架構》P9
對驅動程序作者來說,在 2.6 版內核中刪除了對頁表直接操作的需求。 《LINUX 設備驅動程序》(第三版)P414

1.3 UMA(一致性訪問) / NUMA(非一致性訪問)
UMA (uniform memory access)
NUMA(non-uniform memory access)
UMA 計算機將可用內存以連接方式組織起來。SMP 系統中每個處理器訪問各個內存區都是同樣快。
NUMA 計算機總是多處理器計算機。系統的各個 CPU 都有本地內存,可支持特別快速的訪問。各個處理器之間通過總線連接起來,以支持對其他 CPU 的本地內存訪問,當然比訪問本地內存慢些。
真正的 NUMA 會設置配置選項 CONFIG_NUMA。

《深入 LINUX 內核架構》P108

非一致內存訪問(NUMA)模型,在這種模型中,給定 CPU 對不同內存單元的訪問時間可能不一樣。《深入理解 LINUX 內核》P51

1.4 高端內存和低端內存
虛擬地址空間的內核部分必然小於 CPU 理論地址空間的最大長度。如果物理內存比可以映射到內核地址空間中的數量要多,那麼內核必須藉助於高端內存(highmem)方法來管理“多餘的”內存。

《深入 LINUX 內核架構》P107

使用 32 位系統只能在 4GB 的內存中尋址
在不破壞 32 位應用程序和系統兼容性的情況下,爲了能使用更多的內存,處理器製造廠家爲他們的產品增加了“地址擴展”特性。其結果是在許多情況下,即使 32 位的處理器都可以在大於 4GB 的物理地址空間尋址。
然而有多少內存可以直接映射到邏輯地址的限制依然存在。只有內存的低端部分(依賴與硬件和內核的設置,一般爲 1 到 2GB)用於邏輯地址;剩餘部分(高端內存)是沒有的。在訪問特定的高端內存頁前,內核必須建立明確的虛擬映射,使該頁可在內核地址空間中被訪問。
因此,許多內核數據結構必須被放置在低端內存中;而高端內存更趨向於爲用戶空間進程頁所保留。

《LINUX 設備驅動程序》(第三版)P411

存在於內核空間上的邏輯地址內存。幾乎所有現在讀者遇到的系統,它全部的內存都是低端內存。

是指那些不存在邏輯地址的內存,這是因爲它們處於內核虛擬地址之上。

《LINUX 設備驅動程序》(第三版)P412

64 位地址空間避免了古怪的高端內存域。《深入 LINUX 內核架構》P151

1.5 內存模型
內存模型是從處理器角度看到的物理內存分佈情況,內核管理不同內存模型的方式存在差異。內存管理子系統支持3 種內存模型:
(1) 平坦內存(Flat Memory):內存的物理地址空間是連續的,沒有空洞。
(2) 不連續內存(Discontiguous Memory):內存的物理地址空間存在空洞,這種模型可以高效地處理空洞。
(3) 稀疏內存(Sparse Memory):內存的物理地址空間存在空洞。如果要支持內存熱插拔,只能選擇稀疏內存模型。

《Linux 內核深度解析》P140

2 物理內存的管理
2.1 物理內存的組織:節點和管理區(內存域)簡介
2.1.1 簡介
內存管理子系統使用節點 (node) 、區域 (zone) 和頁 (page) 三級結構描述物理內存。
內存節點使用一個 pglist_data 結構體描述內存佈局。內核定義了宏 NODE_DATA(nid) ,它用來獲取節點的pglist_data 實例。對於平坦內存模型,只有一個 pglist_data 實例 :contig_page_data 。

《Linux 內核深度解析》P141

Linux2.6 支持非一致性內存訪問(NUMA)模型,在這種模型中,給定的 CPU 對不同內存單元的訪問時間可能不一樣。系統的物理內存被劃分爲幾個節點(node)。在一個單獨的節點內,任一給定 CPU 訪問頁面所需時間都是相同的。
每個節點中的物理內存又可以分爲幾個管理區(zone)。
所有節點的描述符存放在一個單向鏈表中,它的第一個元素由 pgdat_list 變量指向。

《深入理解 LINUX 內核》P298

 

內存劃分爲結點。每個結點關聯到系統中的一個處理器,在內核中表示爲 pg_data_t 的實例。
各個結點又劃分爲內存域,是內存的進一步細分。


一個結點由最多 3 個內存域組成。內核引入下列常量來區分它們。
ZONE_DMA: 標記適合 DMA 的內存域。該區域的長度依賴於處理器類型。
ZONE_DMA32: 標記了使用 32 位地址字可尋址、適合 DMA 的內存域。
ZONE_NORMAL: 標記了可直接映射到內核段的普通內存域。
ZONE_HIGHMEM: 標記了超出內核段的物理內存。

《深入 LINUX 內核架構》P109

ZONE_MOVABLE: 它是一個僞內存區域,用來防止內存碎片。
ZONE_DEVICE: 爲支持持久內存(persistent memory)熱插拔增加的內存區域。
《Linux 內核深度解析》P142

2.1.2 備用區域列表 / 區域水線 / 內存域水印
備用區域列表

如果首選的內存節點和區域不能滿足頁分配請求,可以從備用的內存區域借用物理頁,借用必須遵守以下原則。
<1> 一個內存節點的某個區域類型可以從另一個內存節點的相同區域類型借用物理頁,例如節點 0 的普通區域可以從節點 1 的普通區 域借用物理頁。
<2> 高區域類型可以從低區域類型借用物理頁,例如普通區域可以從 DMA 區域借用物理頁。
<3> 低區域類型不能從高區域類型借用物理頁,例如 DMA 區域不能從普通區域借用物理頁。

《Linux內核深度解析》P154

區域水線 / 內存域水印

首選的內存區域在什麼情況下從備用區域借用物理頁?這個問題要從區域水線開始說起。每個內存區域有 3 個水線。
<1> 高水線:如果內存區域的空閒頁數大於高水線,說明該內存區域的內存充足。
<2> 低水線:如果內存區域的空閒頁數小於低水線,說明該內存區域的內存輕微不足。
<3> 最低水線:如果內存區域的空閒頁數小於最低水線,說明該內存區域的內存嚴重不足。
最低水線以下的內存稱爲緊急保留內存。

《Linux 內核深度解析》P156

最低水線以下的內存稱爲緊急保留內存,在內存嚴重不足的緊急情況下,給承諾“給我少量緊急保留內存使用,我可以釋放更多的內存”的進程使用。
設置了進程標誌位 PF_MEMALLOC 的進程可以使用緊急保留內存,標誌位 PF_MEMALLOC 表示“給我少量緊急保留內存使用,我可以釋放更多的內存”。內存管理子系統以外的子系統不應該使用這個標誌位,典型的例子是頁回收內核線程 kswapd ,在回收頁的過程中可能需要申請內存。

《Linux 內核深度解析》P156

相關算法

《Linux 內核深度解析》P157
《深入理解 LINUX 內核》P303

相關/proc/文件

/proc/sys/vm/min_free_kbytes
/proc/sys/vm/watermark_scale_factor 《Linux 內核深度解析》P156 《深入 LINUX 內核架構》P116

/proc/sys/vm/numa_zonelist_order
/proc/zoneinfo 《Linux 內核深度解析》P155

2.1.3 相關函數
NODE_DATA(nid); //它用來獲取節點的 pglist_data 實例;《Linux 內核深度解析》P141

page_to_nid(); //用來得到物理頁所屬的內存節點的編號;《Linux 內核深度解析》P143

 

2.2 夥伴系統
2.2.1 簡介
在內核初始化完成後,內存管理的責任由夥伴系統承擔。夥伴系統基於一種相對簡單然而令人喫驚的強大算法,已經伴隨我們幾乎 40 年。它結合了優秀內存分配器的兩個關鍵特徵:速度和效率。

《深入 LINUX 內核架構》P159

內核中很多時候要求分配連續頁。爲快速檢測內存中的連續區域,內核採用了一種父老而歷經檢驗的技術:夥伴系統

《深入 LINUX 內核架構》P11

Linux 採用著名的夥伴系統(buddy system)算法來解決外碎片問題。《深入理解 LINUX 內核》P312

 

由一個母實體分成的兩個各方面屬性一致的兩個子實體,這兩個子實體就處於夥伴關係。在操作系統分配內存的過程中,一個內存塊常常被分成兩個大小相等的內存塊,這兩個大小相等的內存塊就處於夥伴關係。它滿足 3 個條件 :
• 兩個塊具有相同大小記爲 2^K
• 它們的物理地址是連續的
• 從同一個大塊中拆分出來

https://blog.csdn.net/chm880910/article/details/80342183

2.2.2 夥伴系統實現原理
爲了便於頁面的維護,將多個頁面組成內存塊,每個內存塊都有 2 的方冪個頁,方冪的指數被稱爲階 order。order相同的內存塊被組織到一個空閒鏈表中。夥伴系統基於 2 的方冪來申請釋放內存頁。
當申請內存頁時,夥伴系統首先檢查與申請大小相同的內存塊鏈表中,檢看是否有空閒頁,如果有就將其分配出去,並將其從鏈表中刪除,否則就檢查上一級,即大小爲申請大小的 2 倍的內存塊空閒鏈表,如果該鏈表有空閒內存,就將其分配出去,同時將剩餘的一部分(即未分配出去的一半)加入到下一級空閒鏈表中;如果這一級仍沒有空閒內存;就檢查它的上一級,依次類推,直到分配成功或者徹底失敗,在成功時還要按照夥伴系統的要求,將未分配的內存塊進行劃分並加入到相應的空閒內存塊鏈表
在釋放內存頁時,會檢查其夥伴是否也是空閒的,如果是就將它和它的夥伴合併爲更大的空閒內存塊,該檢查會遞歸進行,直到發現夥伴正在被使用或者已經合併成了最大的內存塊。

https://blog.csdn.net/chm880910/article/details/80342183

2.2.3 /proc/buddyinfo 中獲得夥伴系統的當前信息
參考《深入 LINUX 內核架構》P161

3 slab 分配器
《LINUX 設備驅動程序》(第三版)P217
《Linux 內核設計與實現》P197
《深入理解 LINUX 內核》P323
《深入 LINUX 內核架構》P205

3.1 slab簡介
分配和釋放數據結構是所有內核中最普遍的操作之一。爲了便於數據的頻繁分配和回收,編程人員常常會用到空閒鏈表。空閒鏈表包含可供使用的、已經分配好的數據結構塊。當代碼需要一個新的數據結構實例時,就從空閒鏈表中抓取一個,而不需要分配內存,再把數據放進區。以後,當不再需要這個數據結構的實例時,就把它放回空閒鏈表,而不是釋放它。從這個意義上說,空閒鏈表相當於對象高速緩存——快速存儲頻繁使用的對象類型。

在內核中,空閒鏈表面臨的主要問題之一是不能全局控制。當可以內存變得緊缺時,內核無法通知每個空閒鏈表,讓其收縮緩存的大小以便釋放出一些內存來。實際上內核根本不知道存在空閒鏈表。爲了彌補之一缺陷,也爲了使代碼更加穩固,linux 內核提供了 slab 層(也就是所謂的 slab 分配器)。slab 分配器扮演了通用數據結構緩存層的角色。

《Linux 內核設計與實現》P197

Linux 內核的高速緩存管理有時稱爲“slab 分配器”。 《LINUX 設備驅動程序》(第三版)P217

3.2 常用函數
kmem_cache_create();
《LINUX 設備驅動程序》(第三版)P217
《深入理解 LINUX 內核》P328

kmem_cache_alloc();
《LINUX 設備驅動程序》(第三版)P218
《深入理解 LINUX 內核》P337

kmem_cache_free();
《LINUX 設備驅動程序》(第三版)P218
《深入理解 LINUX 內核》P338

kmem_cache_destroy();

這個釋放操作只有在已將從緩存中分配的所有對象都歸還後才能成功。所以,模塊應該檢查 kmem_cache_destroy 的返回狀態;如果失敗,則表明模塊中發生了內存泄漏(因爲有一些對象被漏掉了)。 《LINUX 設備驅動程序》(第三版)P219

 

kmem_cache_shrink();

kmem_cache_shrink()函數通過調用 slab_destroy()撤銷高速緩存中所有的 slab。《深入理解 LINUX 內核》P329

3.3 /proc/slabinfo
《深入 LINUX 內核架構》P208
《深入理解 LINUX 內核》P329

3.4 /sys/kernel/slab/
Documentation/ABI/testing/sysfs-kernel-slab

3.5 slabtop 命令
《Linux性能優化》P54

3.6 注意點
對嵌入式系統來說,slab 分配器代碼量和複雜性都太高。

爲了處理此類情形,在內核2.6開發期間,增加了slab分配器的兩個替代品:slob和slub。

《深入 LINUX 內核架構》P206

4 vmalloc()和 kmalloc()以及它們之間的區別
4.1 vmalloc() / vfree()
4.1.1 簡介
vmalloc 是一個接口函數,內核代碼使用它來分配在虛擬內存中連續但在物理內存中不一定連續的內存。《深入 LINUX 內核架構》P196

4.1.2 注意點
在大多數情況下不鼓勵使用 vmalloc。通過 vmalloc 獲得的內存使用起來效率不高。 《LINUX 設備驅動程序》(第三版)P225

 

vmalloc 的開銷要比__get_free_pages 大,因爲它不但要獲取內存,還要建立頁表。

vmalloc 函數的一個小缺點是它不能在原子上下文中使用。

《LINUX 設備驅動程序》(第三版)P226

 

vmalloc()僅在不得已時纔會使用——典型的就是爲了獲得大塊內存時,例如,當模塊被動態插入到內核中時,就把模塊裝載到由 vmalloc()分配的內存上。 《Linux 內核設計與實現》P196

 

4.2 kmalloc() / kfree() / kzalloc()
4.2.1 簡介
kmalloc()接口建立在 slab 層之上,使用了一組通用高速緩存。 《Linux 內核設計與實現》P197

每次調用 kmalloc 時,內核找到最適合的緩存,並從中分配一個對象滿足請求(如果沒有剛好適合的緩存,則分配稍大的對象,但不會分配更小的對象)。 《深入 LINUX 內核架構》P209

用 kzalloc 申請內存的時候,效果等同於先是用 kmalloc()申請空間,然後用 memset()來初始化,所有申請的元素都被初始化爲 0。對應的釋放函數也是 kfree 函數。 https://www.cnblogs.com/linhaostudy/p/7477370.html

4.2.2 注意點
對 kmalloc 能夠分配的內存大小,存在一個上限。這個限制隨着體系架構的不同以及內存配置選項的不同而變化。如果我們希望代碼具有完整的可移植性,則不應該分配大於 128KB 的內存。但是,如果希望得到多於幾千字節的內存,則最好使用除了 kmalloc 之外的內存獲取方法。 《LINUX 設備驅動程序》(第三版)P217

 

4.2.3 kmalloc(size, flags)接口中 flags 參數的說明
《LINUX 設備驅動程序》(第三版)P214
《深入 LINUX 內核架構》P174

 

4.x vmalloc()和 kmalloc()的區別
1. kmalloc 和 vmalloc 都是分配的內核的內存。
2. kmalloc 保證分配的內存在物理上是連續的,vmalloc 保證虛擬地址空間上連續,在物理地址空間上可能不連續。
4. kmalloc 能分配的大小有限,vmalloc 能分配的相對較大。
5. 內存只有在要被 DMA 訪問的時候才需要物理上連續。
6. vmalloc 比 kmalloc 要慢。

https://blog.csdn.net/macrossdzh/article/details/5958368

5 __get_free_pages() / alloc_pages_node()
5.1 簡介
仔細觀察內存地址,無論是虛擬的還是物理的,它們都被分爲頁號和一個頁內的偏移量。舉個例子,如果使用頁大小爲 4096 個字節,那麼最後的 12 位是偏移量,而剩餘的高位則指定了頁號。
當系統的 PAGE_SIZE 爲 4096 時,__get_free_page()、__get_free_pages()和 get_zeroed_page()獲取到的 16 進制頁地址的低 3
位是 0。如:
0xffff 8800 86b7 c000
0xffff 8800 994b c000

5.2 常用函數
struct page * alloc_pages_node(int nid, unsigned int flags, unsigned int order); 《LINUX 設備驅動程序》(第三版)P221

 

struct page * alloc_pages(gfp_t gfp_mask, unsigned int order);

struct page * alloc_page(gfp_t gfp_mask);

void __free_pages(struct page *page, unsigned int order);

void __free_page(struct page *page);

 

void * page_address(struct page *page);

unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order);

unsigned long __get_free_page(gfp_t gfp_mask);

unsigned long get_zeroed_page(unsigned int gfp_mask);

void free_pages(unsigned long addr, unsigned long order);

void free_page(unsigned long addr);

《LINUX設備驅動程序》(第三版)P224 《Linux內核設計與實現》P190

 

6 分配函數的選擇
《Linux 內核設計與實現》P209

7 避免內存碎片(反碎片)
7.1 簡介
夥伴系統確實工作得非常好。但是在 Linux 內存管理方面,有一個長期存在的問題:在系統啓動並長期運行後,物理內存會產生很多碎片。 《深入 LINUX 內核架構》P161

通過夥伴系統可以在某種程度上減少內存碎片,但無法完全消除。 《深入 LINUX 內核架構》P12

內核的方式是反碎片(anti-fragmentation),即試圖從最開始儘可能防止碎片。《深入 LINUX 內核架構》P161

內存碎片分爲內部碎片和外部碎片,內部碎片指內存頁裏面的碎片,外部碎片指空閒的內存頁分散,很難找到一組物理地址連續的空閒內存頁。 《Linux 內核深度解析》P288

7.2 反碎片的技術
<1> 2.6.23 版本引入了虛擬可移動區域。
<2> 2.6.23 版本引入了成塊回收(lumpy reclaim,有的書中翻譯爲集中回收),3.5 版本廢除,被內存碎片整理技術取代。成塊回收不是一個完整的解決方案,它只是緩解了碎片問題。
<3> 2.6.24 版本引入了根據可移動性分組的技術,把物理頁分爲不可移動頁、可移動頁和可回收頁 3 種類型。
<4> 2.6.35 版本引入了內存碎片整理技術。

《Linux 內核深度解析》P288

7.3 虛擬可移動區域
7.3.1 簡介
可移動區域(ZONE_MOVABLE)是一個僞內存區域,基本思想很簡單:把物理內存分爲兩個區域,一個區域用於分配不可移動的頁,另一個區域用於分配可移動的頁,防止不可移動頁向可移動區域引入碎片。 《Linux 內核深度解析》P289

7.3.2 使用方法
《Linux 內核深度解析》P289

7.4 根據可移動性分組
爲了預防內存碎片,內核根據可移動性把物理頁分爲 3 種類型。
<1> 不可移動頁:位置必須固定,不能移動,直接映射到內核虛擬地址空間的頁屬於這一類。
<2> 可移動頁:使用頁表映射的屬於這一類,可移動到其它位置,然後修改頁表映射。
<3> 可回收頁:不能移動,但可以回收,需要數據的時候可以重新從數據源獲取。後備存儲設備支持的頁屬於這一類。

《Linux 內核深度解析》P158


<1> 不可移動頁:在內存中有固定的位置,不能移動到其它地方。核心內核分配的大多數內存屬於該類別。
<2> 可回收頁:不能直接移動,但可以刪除,其內存可以從某些源重新生成。例如,映射自文件的數據數據該類別。kswapd 守護進程會根據可回收頁訪問的頻繁程度,週期性的釋放此類內存。
<3> 可移動頁可以隨意移動。屬於用戶空間的應用程序屬於該類別。它們是通過頁表映射的。

《深入 LINUX 內核架構》P162
遷移類型:
MIGRATE_UNMOVABLE,
MIGRATE_RECLAIMABLE,
MIGRATE_MOVABLE,
MIGRATE_PCPTYPES,
......

7.5 內存碎片整理(memory compaction)
7.5.1 簡介
基本思想是:從內存區域的底部掃描已分配的可移動頁,從內存區域的頂部掃描空閒頁,把底部的可移動頁移動到頂部的空閒頁,在底部形成連續的空閒頁。 《Linux 內核深度解析》P291

7.5.2 使用方法
打開內核配置:CONFIG_COMPACTION
向/proc/sys/vm/compact_memory 文件寫入任何整數值(數值沒有意義),觸發內存碎片整理。

文件/proc/sys/vm/compact_unevictable_allowed 用來設置是否允許內存碎片整理移動不可回收的頁,設置爲 1 表示允許。
文件/proc/sys/vm/extfrag_threshold 用來設置外部碎片的閥值,取值範圍 0~1000,默認 500。

《Linux 內核深度解析》P292

8 內存耗盡殺手
8.1 簡介
當內存嚴重不足的時候,頁分配器在多次嘗試直接頁回收失敗後,就會調用內存耗盡殺手(OOM killer,OOM 是“Out of Memory”的縮寫),選擇進程殺死,釋放內存。 《Linux 內核深度解析》P338

8.2 使用方法
內存耗盡殺手沒有配置宏,可配置的參數如下:
<1> /proc/sys/vm/oom_kill_allocating_task ,是否允許殺死正在申請分配內存並觸發內存耗盡的進程。
<2> /proc/sys/vm/oom_dump_tasks ,是否允許內存耗盡殺手殺死進程的時候打印所有用戶進程的內存使用信息。
<3> /proc/sys/vm/panic_on_oom,是否允許在內存耗盡的時候內核恐慌,重啓系統。

《Linux 內核深度解析》P338

8.3 內存耗盡殺手計算進程的壞蛋分數
《Linux 內核深度解析》P338

9 內存資源控制器 / 控制組(cgroup) / 內存控制組(memcg)
9.1 簡介
控制組(cgroup)的內存資源控制器用來控制一組進程的內存使用量,啓用內存資源控制器的指控組簡稱內存控制組(memcg)。控制組把各種資源控制器稱爲子系統,內存資源控制器也稱爲內存子系統。 《Linux 內核深度解析》P340

控制組版本 1 和控制組版本 2 的內存資源控制器是互斥的。如果使用了控制組版本 1 的內存資源控制器,就不能使用控制組版本 2 的內存資源控制器;同樣,如果使用了控制組版本 2 的內存資源控制器,就不能使用控制組版本 1 的內存資源控制器。

《Linux 內核深度解析》P341

9.2 控制組版本 1 的內存資源控制器的配置方法
<1> 在目錄”/sys/fs/cgroup”下掛載 tmpfs 文件系統。
mount -t tmpfs none /sys/fs/cgroup
<2> 在目錄”/sys/fs/cgroup”下創建目錄”memory”
mkdir /sys/fs/cgroup/memory
<3> 在目錄”/sys/fs/cgroup/memory/”下掛載 cgroup 文件系統,把內存資源控制器關聯到控制組層級樹。
mount -t cgroup -o memory none /sys/fs/cgroup/memory/
<4> 創建新的控制組
mkdir /sys/fs/cgroup/memory/memcg0

<5> 設置內存使用的限制。例如把控制組的內存使用限制設置爲 4MB
echo 4M > /sys/fs/cgroup/memory/memcg0/memory.limit_in_bytes
<6> 把線程加入控制組
echo <pid> /sys/fs/cgroup/memory/memcg0/tasks
<7> 頁可以把線程組加入控制組,指定線程組中任意一個線程的標識符,就會把線程組的所有線程加入任務組。
echo <pid> /sys/fs/cgroup/memory/memcg0/cgroup.procs

《Linux 內核深度解析》P342

10 內存錯誤檢測工具 KASAN
10.1 簡介
內核地址消毒劑(Kernel Address SANitizer,KASAN),是一個動態的內存錯誤檢查工具,爲發現“釋放後使用”和“越界訪問”這兩類缺陷提供了快速和綜合的解決方案。 《Linux 內核深度解析》P401

10.2 對編譯器的要求 和 對內核代碼版本的要求
KASAN 使用編譯時插樁檢查每個內存訪問,要求 GCC 編譯器的版本至少是 4.9.2,檢查棧和全局變量的越界訪問需要 GCC 編譯器的版本至少是 5.0


內核支持 KASAN 的進展如下
<1> 4.0 版本引入 KASAN,僅 x86_64 架構支持,只有 SLUB 分配器支持 KASAN。
<2> 4.4 版本的 AMD64 架構支持 KASAN。
<3> 4.6 版本的 SLAB 分配器支持 KASAN。

《Linux 內核深度解析》P401

10.3 使用方法
《Linux 內核深度解析》P401

11 在系統引導時獲取緩衝區(bootmem分配器)
《LINUX 設備驅動程序》(第三版)P230


————————————————
版權聲明:本文爲CSDN博主「u010936265」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u010936265/article/details/108330347

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章