正文:
本文將詳細探討 Linux 核心中的分頁機制,涵蓋記憶體模型、節點與區域劃分、頁面分配策略、核心頁表和頁面交換等核心內容。同時,結合香港伺服器的實際應用場景,分析其在高性能計算中的優化實踐。本教程結構清晰、層次分明,旨在幫助讀者深入理解 Linux 記憶體管理的分頁原理。
一、引言
記憶體管理是作業系統的核心功能之一,確保行程能夠高效利用系統資源,同時維持系統的穩定性和效能。在伺服器等高性能計算環境中,記憶體管理尤為重要,因為這些伺服器通常需要處理大量併發請求、運行多個虛擬機器或容器化應用,並支援高密度的資料中心需求。Linux 作為主流的伺服器作業系統,提供了強大的記憶體管理機制,其中分頁機制是其虛擬記憶體管理的關鍵組成部分。
本文將從以下幾個方面展開討論:
記憶體模型: 平坦記憶體模型、SMP 和 NUMA 的特性與應用。
記憶體的層次劃分: 節點、區域和頁面的組織方式。
頁面分配機制: 夥伴系統和 Slub Allocator 的實作原理。
核心頁表: 初始化和虛擬到實體位址的映射。
頁面交換: 被動回收和主動管理的策略。
透過這些內容,讀者將能夠理解 Linux 記憶體管理中的分頁機制,並認識到其在伺服器等高效能環境中的實際應用價值。
二、記憶體模型概述
Linux 支援多種記憶體模型,以適應不同的硬體架構和效能需求。以下是三種主要記憶體模型的簡介:
2.1 平坦記憶體模型 (Flat Memory Model)
描述: 採用連續的實體位址空間,頁面編號與位址之間存在簡單的線性映射。
優點: 結構簡單,適合早期硬體或小型系統。
缺點: 隨著記憶體需求和行程數量的增加,其擴充性受限,無法滿足現代多處理器系統的複雜需求。
應用場景: 適用於資源受限的嵌入式系統或早期電腦。
2.2 對稱多處理模型 (Symmetric Multi-Processing, SMP)
描述: 允許多個處理器平等存取共享主記憶體,由單一作業系統統一排程。
特點: 透過負載平衡最佳化資源利用率;所有處理器共享同一記憶體空間,可能導致存取爭用。
應用場景: 廣泛用於多核伺服器環境中,提升併發處理能力,適合運行多執行緒應用或虛擬化環境。
2.3 非均勻記憶體存取模型 (Non-Uniform Memory Access, NUMA)
描述: 每個 CPU 擁有本地記憶體,存取本地記憶體的延遲低於遠端記憶體;CPU 和記憶體共同構成 NUMA 節點。
特點: 透過最佳化本地記憶體存取,顯著提高效能;但跨節點存取會增加延遲。
應用場景: 在伺服器中,NUMA 模型透過最佳化記憶體分配,顯著提高高效能計算任務的效率,如資料庫處理或分散式計算。
挑戰: 當本地記憶體不足時,跨節點存取需要核心進行智慧的記憶體分配策略。
總結: 在伺服器中,NUMA 模型尤為重要,因為它能夠更好地適應多處理器架構和高性能需求,減少記憶體存取延遲,提升系統吞吐量。
三、記憶體的層次劃分
Linux 將實體記憶體劃分為節點 (Node)、區域 (Zone) 和頁面 (Page) 三個層次,以實現高效管理。
3.1 節點 (Node)
描述: 在 NUMA 架構中,記憶體被劃分為多個節點,每個節點對應一個 CPU 及其本地記憶體。
結構: 透過
pglist_data結構體描述,包含以下關鍵欄位:node_id:節點唯一標識。node_zones:節點內的區域陣列。node_zonelists:備用節點和區域的鏈結串列。node_mem_map:節點的頁面陣列。node_start_pfn:節點起始頁面框架號。node_present_pages:節點內可用實體頁面總數。node_spanned_pages:節點覆蓋的頁面總數(包括空洞)。kswapd_wait、kswapd等:與頁面回收和交換相關。
應用: 在伺服器中,透過最佳化節點間記憶體分配,減少遠端存取延遲,提升效能。例如,運行高併發應用的伺服器可以透過 NUMA 最佳化降低記憶體存取瓶頸。
3.2 區域 (Zone)
描述: 每個節點進一步劃分為多個區域,儲存在
node_zones中;node_zonelists以鏈結串列形式儲存備用節點和區域資訊;nr_zones表示區域總數。區域類型:
ZONE_DMA:用於直接記憶體存取 (DMA),適用於硬體資料傳輸,解放 CPU 資源。ZONE_NORMAL:直接映射區,覆蓋核心態的低位址空間(32 位元系統中為前 896MB)。ZONE_HIGHMEM:高端記憶體區,適用於 32 位元系統的高位址空間,64 位元系統通常無需此區域。ZONE_MOVABLE:可移動區域,透過劃分可移動和不可移動分配區域,減少記憶體碎片。
結構: 透過
zone結構體管理,包含以下關鍵欄位:zone_start_pfn:區域起始頁面號。spanned_pages:區域總共跨多少頁面。present_pages:區域內真實存在的頁面數。managed_pages:由夥伴系統管理的頁面數。per_cpu_pageset:區分冷熱頁面(熱頁面載入到 CPU 高速快取,存取速度更快)。
應用: 在伺服器中,合理配置區域類型可以最佳化記憶體分配效率,確保關鍵應用(如資料庫或 Web 伺服器)獲得足夠的記憶體資源。
3.3 頁面 (Page)
描述: 頁面是記憶體管理的最小單位,透過
page結構體描述,支援多種用途。用途:
整頁使用:
匿名頁面:直接映射到虛擬位址空間。
記憶體映射檔案頁面:關聯檔案系統,與虛擬位址空間建立映射。
小塊記憶體分配: 透過 Slub Allocator 將頁面切分為小塊,適用於小記憶體分配場景。
複合頁面: 將多個連續頁面視為一個大頁面,最佳化大塊記憶體分配。
結構:
page結構體包含以下關鍵欄位:mapping:映射資訊(匿名頁最低位為 1,檔案映射頁為 0)。index:映射區的偏移量。_mapcount:指向該頁的頁表數。lru:用於頁面交換的鏈結串列。s_mem、freelist等:用於 Slub Allocator 的小塊記憶體管理。
應用: 在伺服器中,頁面管理的效率直接影響到系統的整體效能,尤其是在處理大量小記憶體分配的場景中,如行程建立或資料結構分配。
四、頁面分配機制
Linux 透過夥伴系統 (Buddy System) 和 Slub Allocator 實作頁面分配,滿足不同場景的記憶體需求。
4.1 夥伴系統 (Buddy System)
描述: 適用於分配較大記憶體塊(頁面級別),透過維護多個空閒頁面鏈結串列實現高效分配。
機制:
每個鏈結串列中的節點包含的頁面數為 2 的冪次方,即第
i個鏈結串列的每個節點擁有2^i個頁面。當請求分配
(2^(i-1), 2^i]數目的頁面時,按照2^i頁面請求處理,並將其分裂。如果當前鏈結串列無空閒頁面,則從更大的頁面鏈結串列中找尋並分裂。
實作: 透過
alloc_pages()函數實作,參數包括:gfp_mask:分配區域標誌(如GFP_KERNEL分配ZONE_NORMAL、GFP_HIGHMEM分配高端記憶體等)。order:分配2^order個頁面。
最佳化技術: 交叉存取 (interleaved memory) 將記憶體分為多個模組,類似負載平衡逐個寫入,提高讀寫速度。
應用: 在伺服器中,夥伴系統用於大規模記憶體分配,如虛擬機器或容器的記憶體分配,確保高效的記憶體利用。
4.2 Slub Allocator
描述: 適用於小塊記憶體分配,將從夥伴系統申請的大塊頁面切分為小塊,儲存在快取中。
機制:
每個 Slub 快取區 (
kmem_cache) 對應一種物件類型(如task_struct)。透過
kmem_cache_cpu(快速分配路徑)和kmem_cache_node(慢速分配路徑)實作分配。
分配流程:
快速路徑: 從
kmem_cache_cpu的freelist取得空閒物件。慢速路徑: 當快速路徑失敗時,從
kmem_cache_node的partial鏈結串列取得,或向夥伴系統請求新頁面。
實作: 透過
kmem_cache_alloc_node()和kmem_cache_free()管理分配和釋放。應用: 在伺服器中,Slub Allocator 的效能最佳化對於頻繁的小記憶體分配(如行程建立、資料結構分配)至關重要,特別是在高併發場景下。
五、核心頁表
核心頁表是 Linux 記憶體管理的核心元件,負責虛擬位址到實體位址的映射。
5.1 初始化
描述: 在系統啟動時,透過
setup_arch()呼叫鏈初始化核心頁表。關鍵步驟:
載入
swapper_pg_dir(核心頂級頁目錄)。透過
init_mem_mapping()呼叫鏈(如init_memory_mapping() -> kernel_physical_mapping_init())建立虛擬位址和實體位址的映射。使用
__va和__pa函數進行位址轉換,並透過 CR3 暫存器啟用頁表。
應用: 在伺服器中,快速的頁表初始化確保系統能夠迅速進入運行狀態,支援高效的服務啟動。
5.2 映射
描述: 核心頁表透過多級頁表(如
pgd,pud,pmd,pte)實作虛擬到實體位址的映射。關鍵結構:
swapper_pg_dir:指向頂級頁目錄。level4_ident_pgt:直接映射區頁表。level4_kernel_pgt:核心程式碼區頁表。
特點:
直接映射區 (
ZONE_NORMAL) 透過偏移量實作實體位址和虛擬位址的快速轉換。高端記憶體區 (
ZONE_HIGHMEM) 透過高端記憶體映射機制支援。
應用: 在伺服器中,頁表映射的效率直接影響到記憶體存取速度,尤其在處理大記憶體和高併發場景時。
六、頁面交換
由於虛擬記憶體遠大於實體記憶體,Linux 透過頁面交換機制管理記憶體不足的情況。
6.1 被動頁面回收
描述: 當實體記憶體不足時,透過
get_page_from_freelist()呼叫鏈嘗試回收頁面。機制:
檢查 LRU (最近最少使用) 列表,優先回收不活躍頁面。
對於匿名頁面,分配 swap 空間,將頁面寫入檔案系統。
對於檔案映射頁面,將記憶體中的修改寫回檔案系統。
實作: 透過
node_reclaim() -> __node_reclaim() -> shrink_node()呼叫鏈實作。應用: 在伺服器中,被動回收是防止記憶體耗盡的最後防線,確保系統在高負載下保持穩定。
6.2 主動頁面管理
描述: 核心執行緒
kswapd定期掃描記憶體,根據水位 (watermark) 觸發記憶體回收。水位:
pages_min:最小閾值,僅核心可分配記憶體。pages_low:低閾值,觸發記憶體回收。pages_high:高閾值,記憶體壓力小。
計算:
pages_low = pages_min * 5/4pages_high = pages_min * 3/2
實作: 透過
balance_pgdat() -> kswapd_shrink_node() -> shrink_node()呼叫鏈實作,shrink_node_memcg()管理 LRU 列表,優先回收不活躍頁面。應用: 在伺服器中,主動管理確保記憶體始終處於健康狀態,支援長期穩定運行。
七、總結
Linux 的分頁機制是其記憶體管理系統的核心,涵蓋了從記憶體模型到頁面分配、頁表映射和頁面交換的各個方面。
透過平坦記憶體模型、SMP 和 NUMA 的靈活支援,Linux 能夠適應不同的硬體架構。
透過節點、區域和頁面的層次劃分,實現高效的記憶體管理。
透過夥伴系統和 Slub Allocator,滿足大塊和小塊記憶體分配需求。
透過核心頁表和頁面交換機制,確保虛擬記憶體的高效使用。
在香港伺服器等高效能計算環境中,這些機制不僅確保了記憶體的高效利用,還為高密度資料中心提供了穩定可靠的運行基礎。透過理解這些原理,系統管理員和開發者可以更好地最佳化伺服器效能,滿足現代應用的需求。
參考資料:
Linux 核心記憶體管理
Linux 記憶體管理相關資料結構
Linux 分頁機制概述