萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 作業系統 >  >> Linux 教學

Linux 記憶體管理深度解析:虛擬記憶體、頁表、TLB、Swap 與效能調優實戰

從硬體架構到核心機制,全方位掌握 Linux 記憶體子系統

記憶體是系統效能的關鍵。本文深入剖析 32/64 位元架構下的虛擬記憶體映射、頁表分級、TLB 快取、頁面置換演算法、Swap 機制、OOM Killer、記憶體區域劃分,並提供實戰調優參數與監控指標。

一、虛擬記憶體與位址空間

32 位元系統(x86)

  • 每進程 4GB 虛擬位址空間:3GB 用戶空間 + 1GB 核心空間
  • 核心空間再劃分:
    • 0 ~ 16MB:ZONE_DMA(ISA DMA 可尋址範圍)
    • 16MB ~ 896MB:ZONE_NORMAL(核心直接映射,線性映射物理記憶體)
    • 896MB ~ 1GB:ZONE_HIGHMEM(核心無法直接映射,需 kmap 臨時映射)
  • 物理記憶體 > 1GB 時,超過 896MB 屬於 High Memory,核心存取需額外映射步驟,效能損耗

64 位元系統(x86_64)

  • 虛擬位址空間 128TB(47 位元),用戶/核心各半
  • 核心直接映射所有物理記憶體(無 Highmem 問題)
  • ZONE_DMA:0 ~ 4GB(DMA32)
  • ZONE_NORMAL:4GB 以上(核心直接可達)
  • 這是為何生產環境強制要求 64 位元 OS 的核心原因

二、頁表與位址轉換

多級頁表架構

# x86_64 4 級頁表(4KB 頁)
CR3 (PML4) → PML4 Entry → PDP (Page Directory Pointer) → PD (Page Directory) → PT (Page Table) → Physical Page

# 32 位元 PAE 模式 3 級頁表
CR3 → PDP → PD → PT → Page
  • 每級 512 個入口(9 bits),頁面大小 4KB(12 bits offset)
  • 大頁面:2MB (HugeTLB)、1GB (巨型頁),減少頁表層級、降低 TLB miss

TLB (Translation Lookaside Buffer)

  • CPU 內建快取,儲存虛擬→物理映射
  • 命中:零延遲;未命中:硬體/軟體走頁表(昂貴)
  • 大頁面可大幅提升 TLB 覆蓋率,減少 miss
  • Context Switch 會刷新 TLB(PCID 技術可緩解)

三、頁面置換與 Swap 機制

LRU (Least Recently Used) 近似演算法

  • Active/Inactive 雙鏈表近似 LRU
  • Page Reclaim(kswapd/kcompactd)周期性掃描非活躍頁面
  • Anonymous pages → Swap;File-backed pages → 直接捨棄(可從磁碟重讀)

Swap 空間類型

  • Swap 分區:效能最佳,連續空間
  • Swap 檔案:彈性調整大小,現代核心效能差距極小
  • ZRAM/ZSWAP:記憶體內壓縮交換,適合記憶體受限嵌入式/容器

Swappiness 參數(/proc/sys/vm/swappiness)

  • 0:盡量不使用 swap(積極回收 page cache)
  • 60:預設值,平衡
  • 100:積極使用 swap
  • 生產建議:vm.swappiness=10(資料庫/低延遲服務),=60(一般應用)

四、OOM Killer 機制

觸發條件

  • 可用記憶體 + Swap 耗盡
  • 核心無法分配頁面滿足請求

分數計算 (oom_score)

oom_score = 基礎分數 + 調整因子
# 基礎分數:佔用記憶體比例
# 調整:oom_score_adj (-1000 ~ 1000,-1000 永不殺死)
# 關鍵進程保護:echo -1000 > /proc//oom_score_adj

檢視與調整

cat /proc//oom_score
cat /proc//oom_score_adj
# 永久配置:/etc/sysctl.d/99-oom.conf
vm.oom_kill_allocating_task = 0
vm.panic_on_oom = 0

五、記憶體區域與分配器

Zone 分配器

  • ZONE_DMA / ZONE_DMA32 / ZONE_NORMAL / ZONE_HIGHMEM / ZONE_MOVABLE
  • 分配請求按區域優先序嘗試,失敗則 fallback 到下一區域
  • cat /proc/zoneinfo 查看各區域水位線

Slab 分配器

  • kmalloc/slab:小塊物件快取(inode、dentry、task_struct 等)
  • slabtop 觀察快取使用狀況
  • SLUB(預設)、SLAB、SLOB 三種實作

六、關鍵調優參數

# /etc/sysctl.d/99-memory.conf
# Swap 激進度
vm.swappiness = 10

# Dirty page 回寫控制(避免大量髒頁一次寫入造成延遲尖峰)
vm.dirty_ratio = 15           # 髒頁佔比上限觸發同步寫入
vm.dirty_background_ratio = 5 # 背景回寫啟動閾值
vm.dirty_expire_centisecs = 3000  # 髒頁最老壽命 30 秒
vm.dirty_writeback_centisecs = 500 # 背景回寫間隔 5 秒

# 記憶體過量分配
vm.overcommit_memory = 1      # 1=總是允許(適合 Redis/資料庫),0=啟發式,2=嚴格
vm.overcommit_ratio = 50      # overcommit_memory=2 時的實體+swap 比例

# HugePages(資料庫/大記憶體應用)
vm.nr_hugepages = 1024        # 2MB 頁 × 1024 = 2GB
# 需在 /etc/security/limits.conf 給用戶 memlock 權限

# 避免 OOM 殺死關鍵進程
vm.oom_kill_allocating_task = 0
vm.panic_on_oom = 0

七、監控與診斷工具

工具用途關鍵指標
free -h整體記憶體使用available(真正可用)、buff/cache
vmstat 1虛擬記憶體統計si/so(swap in/out)、bi/bo(block IO)、cs(context switch)
pidstat -r 1進程記憶體統計RSS、VSZ、MinFLT、MajFLT(缺頁中斷)
smemPSS/USS 精確記憶體共享記憶體比例分攤
pmap -x PID進程記憶體映射詳情各段權限、RSS、Dirty
/proc/meminfo核心記憶體詳細資訊SReclaimable、SUnreclaim、PageTables、KernelStack
numastatNUMA 節點記憶體分布跨節點存取比例

八、NUMA 架構考量

  • 多插槽伺服器每顆 CPU 有本地記憶體,跨節點存取延遲較高
  • numactl --hardware 查看拓撲
  • 應用綁定:numactl --cpunodebind=0 --membind=0 ./app
  • 核心參數:vm.zone_reclaim_mode = 1(嘗試本地回收而非跨節點分配)

九、容器記憶體限制

# Docker
docker run -m 2g --memory-swap 4g --oom-kill-disable=false ...

# K8s
resources:
  limits:
    memory: "2Gi"
  requests:
    memory: "1Gi"
# 容器內 /sys/fs/cgroup/memory/memory.limit_in_bytes 反映限制

十、實戰檢查清單

  1. 確認 64 位元 OS、核心版本 ≥ 4.x
  2. 設定 vm.swappiness=10、dirty_ratio 適中
  3. 資料庫/大記憶體應用配置 HugePages
  4. 關鍵進程設定 oom_score_adj=-1000
  5. 監控 Major Faults、Swap IO、OOM Kill 事件
  6. NUMA 系統驗證記憶體本地化比例 > 90%
  7. 容器環境設定合理 limits/requests,避免 OOM Kill 連鎖
copyright © 萬盛學電腦網 all rights reserved