自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

認識 Linux 內(nèi)存構(gòu)成:Linux 內(nèi)存調(diào)優(yōu)之頁表、TLB、缺頁異常、大頁認知

系統(tǒng) Linux
當(dāng)啟動一個程序時,會先給程序分配合適的虛擬地址空間,但是不需要把所有虛擬地址空間都映射到物理內(nèi)存,而是把程序在運行中需要的數(shù)據(jù),映射到物理內(nèi)存,需要時可以再動態(tài)映射分配物理內(nèi)存因為每個進程都維護著自己的虛擬地址空間,每個進程都有一個頁表來定位虛擬內(nèi)存到物理內(nèi)存的映射,每個虛擬內(nèi)存也在表中都有一個對應(yīng)的條目。

認識 Linux 內(nèi)存構(gòu)成:Linux 內(nèi)存調(diào)優(yōu)之頁表、TLB、大頁認知

當(dāng)啟動一個程序時,會先給程序分配合適的虛擬地址空間,但是不需要把所有虛擬地址空間都映射到物理內(nèi)存,而是把程序在運行中需要的數(shù)據(jù),映射到物理內(nèi)存,需要時可以再動態(tài)映射分配物理內(nèi)存

因為每個進程都維護著自己的虛擬地址空間,每個進程都有一個頁表來定位虛擬內(nèi)存到物理內(nèi)存的映射,每個虛擬內(nèi)存也在表中都有一個對應(yīng)的條目。

這里的頁表是進程用于跟蹤虛擬內(nèi)存到物理內(nèi)存的映射,那么實際的數(shù)據(jù)結(jié)構(gòu)是什么的?

頁表

如果每個進程都分配一個大的頁表,64位系統(tǒng) 理論虛擬地址空間為2^64字節(jié),但實際 Linux 系統(tǒng)通常采用48位有效虛擬地址

┌──[root@liruilongs.github.io]-[~]
└─$cat /proc/cpuinfo | grep address
address sizes   : 45 bits physical, 48 bits virtual
address sizes   : 45 bits physical, 48 bits virtual
┌──[root@liruilongs.github.io]-[~]
└─$

即2 ^48字節(jié)(256TB)。若頁面大小為4KB(2^12字節(jié)),則需管理的頁表項數(shù)量為 虛擬頁數(shù) = 2^48 / 2^12 = 2^36

每個頁表項需要存儲物理頁幀號(PFN)和權(quán)限標志,通常占用8字節(jié)。所以頁表的總內(nèi)存需求為: 總大小 = 2^36 × 8 = 2^39 字節(jié) = 512GB

512G ,即一個進程的頁表本身就是巨大的,如果多個進程更夸張,但是實際中進程僅使用少量內(nèi)存(如1GB),可能只需要幾個映射,單級頁表仍需預(yù)分配全部虛擬地址空間對應(yīng)的頁表項,造成大部分的空間浪費,況且也沒有那么多內(nèi)存存放頁表。

多級頁表

這里優(yōu)化的方案就是將頁面分級管理(多級頁表 Multi-Level Page Table),將一個大頁表大小分成很多小表,最終指向頁表條目(一條映射記錄),系統(tǒng)只需要給進程分配頁表目錄,從而降低映射總表的大小。

這里怎么理解多級頁表和頁表目錄?

想象你要管理一個超大的圖書館(相當(dāng)于虛擬地址空間),里面有 幾百萬本書(相當(dāng)于內(nèi)存頁)。如果用一個超大的總目錄(只有小標題)記錄每本書的位置,這個目錄本身就會占據(jù)整個圖書館的空間,顯然不現(xiàn)實。多級頁表就像是對只有小標題的目錄作了多級目錄劃分。

  • 第一層目錄(PGD):記錄整個圖書館分為 512個大區(qū)(每個大區(qū)對應(yīng)9位索引,2?=512)。
  • 第二層目錄(PUD):每個大區(qū)再分為 512個小區(qū)。
  • 第三層目錄(PMD):每個小區(qū)再分 512個書架。
  • 第四層目錄(PTE):每個書架對應(yīng) 512本書(每本書即4KB內(nèi)存頁)

我們知道數(shù)組存儲只存儲首地址,之后的元素會根據(jù)首地址計算,這里的頁表目錄類似首地址,所以可以通過多級目錄位置直接定位映射記錄。

現(xiàn)代系統(tǒng)多使用上面多級頁表(如 x86-64 的 四級頁表)的方式,逐步縮小搜索范圍,但是多級頁表也有一定的弊端,后面我們會討論

首先會按照上面的方式對 48位虛擬地址進行拆分,虛擬地址被分割為多個索引字段,每一級索引對應(yīng)一級頁表,逐級查詢頁表項(PTE),48 位虛擬地址可能拆分為:

PGD索引(9位) → PUD索引(9位) → PMD索引(9位) → PTE索引(9位) → 頁內(nèi)偏移(12位)

每級頁表僅需512(2^9)項(9位索引),每個表項是 8 字節(jié),所以單級占用4KB,而且僅在實際需要時分配下級頁表。

當(dāng)進程需要映射1GB內(nèi)存時,只需要分配必要的頁表僅需

總頁表大小 = 1(PGD)+1(PUD)+1(PMD)+512(PTE) = 515×4KB ≈ 2.02MB

PGD、PUD、PMD各一個,PTE需要512個,總共515個頁表項,每個4KB,總共約2.02MB。

那么這里的 512個索引頁面是如何計算的?

1GB/4KB=262,144個頁面, 262,144/512=512 個PTE索引頁(一個索引頁存放512頁表項),一個頁表項對應(yīng)一個內(nèi)存頁

前面我們也有講過,在具體的分配上,內(nèi)核空間位于虛擬地址的高位(高24位),用戶態(tài)內(nèi)存空間位于虛擬地址低位,頁表本身存儲在內(nèi)核空間,用戶程序無法直接修改,僅能通過系統(tǒng)調(diào)用請求內(nèi)核操作。用戶態(tài)程序申請內(nèi)存時,內(nèi)核僅分配虛擬地址,實際物理頁的分配由缺頁異常觸發(fā)。此時內(nèi)核介入,更新頁表項并映射物理頁,這一過程需切換到內(nèi)核態(tài)執(zhí)行。

那里這里的缺頁異常又是什么?

缺頁異常

當(dāng)進程訪問系統(tǒng)沒有映射物理頁的虛擬內(nèi)存頁時,內(nèi)核就會產(chǎn)生一個 page fault 異常事件。

minor fualt

當(dāng)進程缺頁事件發(fā)生在第一次訪問虛擬內(nèi)存時,虛擬內(nèi)存已分配但未映射(如首次訪問、寫時復(fù)制、共享內(nèi)存同步)物理地址,內(nèi)核會產(chǎn)生一個 minor page fualt,并分配新的物理內(nèi)存頁。minor page fault 產(chǎn)生的開銷比較小。

minor page fualt 典型場景:

  • 首次訪問:進程申請內(nèi)存后,內(nèi)核延遲分配物理頁(Demand Paging),首次訪問時觸發(fā)。
  • 寫時復(fù)制(COW):fork()創(chuàng)建子進程時共享父進程內(nèi)存,子進程寫操作前觸發(fā)
  • 共享庫加載:動態(tài)鏈接庫被多個進程共享,首次加載到物理內(nèi)存時觸發(fā),即會共享頁表

major fault

當(dāng)物理頁未分配且需從磁盤(Swap分區(qū)或文件)加載數(shù)據(jù),內(nèi)核就會產(chǎn)生一個 majorpage fault,比如內(nèi)核通過Swap分區(qū),將內(nèi)存中的數(shù)據(jù)交換出去放到了硬盤,需要時從硬盤中重新加載程序或庫文件的代碼到內(nèi)存。涉及到磁盤I/O,因此一個major fault對性能影響比較大,典型場景有

  • Swap In:物理內(nèi)存不足時,內(nèi)核將內(nèi)存頁換出到 Swap 分區(qū),再次訪問需換回。
  • 文件映射(mmap):通過 mmap 映射文件到內(nèi)存,首次訪問文件內(nèi)容需從磁盤讀取。

Minor Fault 是內(nèi)存層面的輕量級操作,Major Fault 是涉及磁盤I/O的重型操作。頻繁的 Major Fault 就需要考慮性能問題, 對于缺頁異常,我們通過 ps、vmstat、perf等工具定位性能瓶頸

通過 ps 命令查看當(dāng)前系統(tǒng)存在缺頁異常的進程的排序

┌──[root@liruilongs.github.io]-[~]
└─$ps -eo pid,minflt,majflt,comm | awk '$2 > 0 && $3 > 0 {print}'
    PID MINFLT MAJFLT COMMAND
      1  55646    189 systemd
    704    959      7 systemd-journal
    719   1912      2 systemd-udevd
    892     80      3 auditd
    913    553     12 dbus-broker-lau
    915    281      4 dbus-broker
    918  15617    206 firewalld
    919    325      6 irqbalance
    921    740      5 systemd-logind
    925    166      5 chronyd
    955   1243    100 NetworkManager
    991  26090    281 /usr/sbin/httpd
    998   2683    260 php-fpm
    999    923     17 sshd
   1002   9775      7 tuned
   1006    862      3 crond
   1121   6976    225 mariadbd
   1150   2060    125 polkitd
   1213    731     24 rsyslogd
   1498    390      7 pmcd
   1518    516     11 pmdaroot
   1535    470      4 pmdaproc
   1544    410      2 pmdaxfs
   1551    447      4 pmdalinux
   1558    409      2 pmdakvm
   1872   2109      1 /usr/sbin/httpd
   1874   3701      9 /usr/sbin/httpd
   2201   2654      2 bash
   2245    678      6 sudo
   2246   3300      1 bash
   4085    541     10 htop
┌──[root@liruilongs.github.io]-[~]
└─$

也可以通過 perf stat 來查看指定命令,進程的 缺頁異常情況

┌──[root@liruilongs.github.io]-[~]
└─$perfstat -e minor-faults,major-faults hostnamectl
 Static hostname: liruilongs.github.io
       Icon name: computer-vm
         Chassis: vm ?
      Machine ID: 7deac2815b304f9795f9e0a8b0ae7765
         Boot ID: 5041b68a4d574df2b59289e33e85bdd5
  Virtualization: vmware
Operating System: Rocky Linux 9.4 (Blue Onyx)
     CPE OS Name: cpe:/o:rocky:rocky:9::baseos
          Kernel: Linux 5.14.0-427.20.1.el9_4.x86_64
    Architecture: x86-64
 Hardware Vendor: VMware, Inc.
  Hardware Model: VMware Virtual Platform
Firmware Version: 6.00

 Performance counter stats for'hostnamectl':

               463      minor-faults
                 0      major-faults

       0.132397887 seconds time elapsed

       0.009642000 seconds user
       0.004471000 seconds sys


┌──[root@liruilongs.github.io]-[~]
└─$

可以看到 hostnamectl 命令因內(nèi)存動態(tài)分配觸發(fā)了 463 次次缺頁中斷,下面是一些常見的對應(yīng)缺頁異常的調(diào)優(yōu)建議

減少 Major Fault:

  • 增加或者禁用物理內(nèi)存:避免頻繁 Swap。
  • 調(diào)整 Swappiness:降低內(nèi)核參數(shù) /proc/sys/vm/swappiness,減少內(nèi)存換出傾向。
  • 預(yù)加載數(shù)據(jù):使用 mlock() 鎖定關(guān)鍵內(nèi)存頁(如實時系統(tǒng)),禁止換出。
  • 優(yōu)化文件訪問:對 mmap 文件進行順序讀取或預(yù)讀(posix_fadvise)。

降低 Minor Fault:

  • 預(yù)分配內(nèi)存:避免 Demand Paging 的延遲(如啟動時初始化全部內(nèi)存)。
  • 減少 COW 開銷:避免頻繁 fork(),改用 posix_spawn 或線程。

通過多級頁表的方式極大的縮小和頁表空間,可以按需分配,但是多級頁表也有一定的局限性,一是地址轉(zhuǎn)換復(fù)雜度,層級增加會降低轉(zhuǎn)換效率,需依賴硬件加速(如MMU的并行查詢能力)。二是內(nèi)存碎片風(fēng)險,子表的離散分配可能導(dǎo)致物理內(nèi)存碎片化(內(nèi)存不連續(xù)+頻繁的回收創(chuàng)建),需操作系統(tǒng)優(yōu)化分配策略

為了解決多級頁表的地址轉(zhuǎn)換需多次訪存(如四級頁表需4次內(nèi)存訪問),導(dǎo)致延遲增加,常見的解決方案包括:

  • TLB(快表)緩存:存儲最近使用的頁表項,命中時直接獲取物理地址,減少訪存次數(shù)
  • 巨型頁(Huge Page):使用2MB或1GB的頁面粒度,減少頁表層級和項數(shù)(大頁的使用需要操作系統(tǒng)和應(yīng)用程序的支持)

所以進程通過頁表查詢虛擬地址和物理地址的映射關(guān)系, 首先會檢查  TLB(Translation Lookaside Buffer)高速緩存頁表項,CPU硬件緩存.

那么這里的 TLB 是如何參與到到內(nèi)存映射的?

TLB

TLB 是內(nèi)存管理單元(MMU)的一部分,本質(zhì)是頁表的高速緩存,存儲最近被頻繁訪問的頁表項(虛擬地址到物理地址的映射關(guān)系)的副本,是集成在 CPU 內(nèi)部的 高速緩存硬件,用于加速虛擬地址到物理地址轉(zhuǎn)換的專用緩存,通過專用電路實現(xiàn)高速地址轉(zhuǎn)換,與數(shù)據(jù)緩存(Data Cache)和指令緩存(Instruction Cache)并列,共同構(gòu)成 CPU 緩存體系

上面我們講當(dāng)進程查詢分層頁面的映射信息會導(dǎo)致延遲增加。因此,當(dāng)缺頁異常觸發(fā)內(nèi)核分配物理內(nèi)存將從虛擬地址到物理地址的映射添加到頁表中時,它還將該映射條目緩存在 TLB 硬件緩存中,通過緩存進程最近使用的頁映射來加速地址轉(zhuǎn)換。

當(dāng)下一次查詢發(fā)生的時候,首先會在 TLB  中查詢是否有緩存,如果有的話會直接獲取,沒有的話,走上面缺頁異常的流程

進程訪問虛擬地址 → MMU 查詢 TLB → [命中 → 直接獲取物理地址]
                │
                └→ [未命中 → 查詢頁表 → 權(quán)限檢查 → 缺頁處理(可選)→ 生成物理地址 → 更新 TLB]
                │
                └→ 訪問物理內(nèi)存

所以 TLB 命中率直接影響程序效率。若 TLB 未命中(Miss),需通過頁表遍歷獲取物理地址,導(dǎo)致額外延遲(通常是 TLB 命中時間的數(shù)十倍),從內(nèi)存加載頁表項,并更新TLB緩存(可能觸發(fā)條目替換,如LRU算法)

可以通過 perf stat 命令來查看某一個命令或者進程的 TLB 命中情況

┌──[root@liruilongs.github.io]-[~]
└─$perfstat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses hostnamectl
 Static hostname: liruilongs.github.io
       Icon name: computer-vm
         Chassis: vm ?
      Machine ID: 7deac2815b304f9795f9e0a8b0ae7765
         Boot ID: 5041b68a4d574df2b59289e33e85bdd5
  Virtualization: vmware
Operating System: Rocky Linux 9.4 (Blue Onyx)
     CPE OS Name: cpe:/o:rocky:rocky:9::baseos
          Kernel: Linux 5.14.0-427.20.1.el9_4.x86_64
    Architecture: x86-64
 Hardware Vendor: VMware, Inc.
  Hardware Model: VMware Virtual Platform
Firmware Version: 6.00

 Performance counter stats for'hostnamectl':

                 0      dTLB-loads
                 0      dTLB-load-misses
   <not supported>      iTLB-loads
                 0      iTLB-load-misses

       0.131288737 seconds time elapsed

       0.010681000 seconds user
       0.005377000 seconds sys


┌──[root@liruilongs.github.io]-[~]
  • dTLB-loads 表示數(shù)據(jù)地址轉(zhuǎn)換(Data TLB)的加載次數(shù),
  • dTLB-load-misses 表示未命中次數(shù)
  • iTLB-loads 表示指令地址轉(zhuǎn)換(Instruction TLB)的加載次數(shù)
  • iTLB-load-misses 指令 TLB 未命中次數(shù)為 0,說明所有指令訪問均命中 TLB 緩存。

查看指定進程的命中情況使用 -p <pid> 的方式

┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$perf stat -e dTLB-loads,dTLB-load-misses,iTLB-loads,iTLB-load-misses -p 1
┌──[root@liruilongs.github.io]-[/usr/lib/systemd/system] 
└─$

大頁(巨型頁)

大頁是另一種解決多級頁表多次訪問內(nèi)存的手段,顧名思義,傳統(tǒng)的內(nèi)存頁是 4KB,大于 4KB 的內(nèi)存頁被稱為大頁,通過大頁可以降低多級頁表的層級

同時 TLB 也有一定的局限性,存儲條目是固定的,當(dāng)進程需要訪問大量內(nèi)存的時候,比如數(shù)據(jù)庫應(yīng)用,將會導(dǎo)致大量 TLB 未命中而影響性能,還是需要通過多級頁表來轉(zhuǎn)化地址,所以除了 4KB 頁面之外,Linux 內(nèi)核還通過大頁面機制支持大容量內(nèi)存頁面。

通過查看 /proc/meminfo 文件確定具體系統(tǒng)的大頁大小以及使用情況,大頁分為 標準大頁(靜態(tài)大頁)和透明大頁

靜態(tài)大頁其核心原理是通過增大內(nèi)存頁的尺寸(如2MB或1GB),優(yōu)化虛擬地址到物理地址的轉(zhuǎn)換效率,從而提升系統(tǒng)性能。x86 64 位架構(gòu)支持多種大頁規(guī)格,比如 4KiB,2MiB 以及 1GiB。Linux 系統(tǒng)默認是 2MiB

需要說明的是,大頁配置僅受用語支持大頁的應(yīng)用程序,對于不支持大頁的應(yīng)用程序來說是無效的,同時大頁會導(dǎo)致內(nèi)存剩余空間變小 后面我們會介紹幾個Demo

透明大頁用于合并傳統(tǒng)內(nèi)存頁。

┌──[root@liruilongs.github.io]-[~]
└─$cat /proc/meminfo | grep Hug
AnonHugePages:    165888 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
┌──[root@liruilongs.github.io]-[~]
└─$

Hugepagesize: 2048 kB: 靜態(tài)大頁的默認大小為 2MB,這里的大頁是標準大頁,若需使用 1GB 大頁,需修改內(nèi)核參數(shù)配置,前提是需要CPU 支持才行

AnonHugePages:    165888 kB:  透明大頁(Transparent HugePages) 匿名頁占用的內(nèi)存總量為 165,888 KB(約 162 MB)

大部分部署數(shù)據(jù)庫的機器會禁用透明大頁?這是什么原因

透明大頁

透明大頁(Transparent Huge Pages,THP)是內(nèi)核提供的一種動態(tài)內(nèi)存管理機制,它通過自動將多個 4KB 小頁 合并為 2MB 或 1GB 大頁,減少頁表項數(shù)量并提升 TLB(地址轉(zhuǎn)換緩存)命中率,從而優(yōu)化內(nèi)存訪問性能

與需手動預(yù)分配的靜態(tài)大頁(HugeTLB)不同,THP 對應(yīng)用程序透明且無需配置,適用于順序內(nèi)存訪問(如大數(shù)據(jù)處理)和低實時性場景。但動態(tài)合并可能引發(fā) 內(nèi)存碎片 和 性能抖動,因此對延遲敏感的數(shù)據(jù)庫(如 MySQL)或高并發(fā)系統(tǒng)建議關(guān)閉 THP

下面為透明大頁相關(guān)配置

┌──[root@liruilongs.github.io]-[~] 
└─$ls /sys/kernel/mm/transparent_hugepage/
defrag          enabled         hpage_pmd_size  khugepaged/     shmem_enabled   use_zero_page

enabled 用于配置是否開啟 THP

┌──[root@liruilongs.github.io]-[~]
└─$cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
┌──[root@liruilongs.github.io]-[~]
└─$cat /proc/meminfo | grep Anon
AnonPages:        356692 kB
AnonHugePages:    167936 kB
┌──[root@liruilongs.github.io]-[~]
└─$

禁用透明大頁 某些場景(如數(shù)據(jù)庫)建議禁用 THP 以穩(wěn)定性能:

# 臨時禁用
echo never > /sys/kernel/mm/transparent_hugepage/enabled

使用 grubby 更新內(nèi)核啟動參數(shù),grubby 用于 動態(tài)修改內(nèi)核啟動參數(shù) 或 設(shè)置默認內(nèi)核,無需手動編輯配置文件

# 永久禁用
┌──[root@liruilongs.github.io]-[~] 
└─$grubby --update-kernel=ALL --args="transparent_hugepage=never"
┌──[root@liruilongs.github.io]-[~] 
└─$reboot

確認配置

┌──[root@liruilongs.github.io]-[~] 
└─$cat /sys/kernel/mm/transparent_hugepage/enabled
always madvise [never]
┌──[root@liruilongs.github.io]-[~] 
└─$

再次查看透明大頁使用情況

┌──[root@liruilongs.github.io]-[~] 
└─$grep AnonHugePages /proc/meminfo
AnonHugePages:         0 kB
┌──[root@liruilongs.github.io]-[~] 
└─$

shmem_enabled 用于配置 共享內(nèi)存(如 tmpfs、共享匿名映射)是否啟用透明大頁(THP)

┌──[root@liruilongs.github.io]-[~] 
└─$cat  /sys/kernel/mm/transparent_hugepage/shmem_enabled 
always within_size advise [never] deny force

這里的 never 表示完全禁用共享內(nèi)存的透明大頁。常用于數(shù)據(jù)庫(如 Oracle、MySQL)或高延遲敏感型應(yīng)用,避免因動態(tài)內(nèi)存合并引發(fā)性能抖動

透明大頁會涉及到一個進程 khugepaged,khugepaged 是 Linux 內(nèi)核的一部分,負責(zé)處理透明大頁(Transparent HugePages, THP)的管理。透明大頁是內(nèi)核自動將小頁合并為大頁以提升性能的機制,而 khugepaged 就是負責(zé)這個合并過程的守護進程。自動掃描內(nèi)存區(qū)域,尋找可以合并的小頁,并嘗試將它們轉(zhuǎn)換為透明大頁。此過程在后臺靜默運行,無需應(yīng)用程序顯式請求。

┌──[root@liruilongs.github.io]-[/sys/devices/system/node] 
└─$ps -eaf | grep khug
root          44       2  0 4月23 ?       00:00:00 [khugepaged]
root       16049    9747  0 10:49 pts/0    00:00:00 grep --color=auto khug

它會嘗試將多個常規(guī)小頁(4KB)合并成 大頁(2MB 或 1GB),以減少頁表項數(shù)量,從而提升內(nèi)存訪問性能。

控制 khugepaged 的掃描頻率,合并閾值等可以通過下面的文件修改

┌──[root@liruilongs.github.io]-[/sys/devices/system/node] 
└─$cat /sys/kernel/mm/transparent_hugepage/khugepaged/alloc_sleep_millisecs
60000
┌──[root@liruilongs.github.io]-[/sys/devices/system/node] 
└─$cat  /sys/kernel/mm/transparent_hugepage/khugepaged/scan_sleep_millisecs
10000
┌──[root@liruilongs.github.io]-[/sys/devices/system/node] 
└─$

靜態(tài)大頁

靜態(tài)大頁需要單獨配置,使用 sysctl 修改內(nèi)核參數(shù),可以設(shè)置分配的靜態(tài)大頁的數(shù)量,大頁內(nèi)存是系統(tǒng)啟動時或通過 sysctl 預(yù)先分配的,這部分內(nèi)存會被鎖定,普通進程無法使用,所以配置需要考慮清楚

┌──[root@liruilongs.github.io]-[~]
└─$sysctl -a | grep huge
vm.hugetlb_optimize_vmemmap = 0
vm.hugetlb_shm_group = 0
vm.nr_hugepages = 0
vm.nr_hugepages_mempolicy = 0
vm.nr_overcommit_hugepages = 0

vm.nr_hugepages:表示系統(tǒng)要預(yù)留的 大頁數(shù)量,通過 -w 臨時配置內(nèi)核參數(shù),配置大頁數(shù)量為 50

┌──[root@liruilongs.github.io]-[~]
└─$sysctl -w vm.nr_hugepages=50
vm.nr_hugepages = 50

確認配置

┌──[root@liruilongs.github.io]-[~]
└─$sysctl -a | grep huge
vm.hugetlb_optimize_vmemmap = 0
vm.hugetlb_shm_group = 0
vm.nr_hugepages = 50
vm.nr_hugepages_mempolicy = 50
vm.nr_overcommit_hugepages = 0

永久生效將配置寫入 /etc/sysctl.conf 并執(zhí)行 sysctl -p

可以通過 grub 修改內(nèi)核參數(shù)來設(shè)置大頁的數(shù)量以及大小

/etc/default/grub 是 Linux 系統(tǒng)中用于配置 GRUB(GRand Unified Bootloader) 引導(dǎo)程序的核心文件。GRUB 是大多數(shù) Linux 發(fā)行版默認的啟動管理器,負責(zé)在系統(tǒng)啟動時加載內(nèi)核和初始化內(nèi)存盤(initramfs)。該文件定義了 GRUB 的全局行為和啟動菜單的默認選項。和 上面 grubby 的方式略有區(qū)別

  • hugepages=N : 設(shè)置大頁的數(shù)量
  • hugepagesz=N 或 default_hugepagesz=N 設(shè)置大頁大小(默認 2MiB)

下面是一個Demo

┌──[root@liruilongs.github.io]-[~]
└─$cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="crashkernel=1G-4G:192M,4G-64G:256M,64G-:512M resume=/dev/mapper/rl-swap rd.lvm.lv=rl/root rd.lvm.lv=rl/swap"
GRUB_DISABLE_RECOVERY="true"
GRUB_ENABLE_BLSCFG=true
┌──[root@liruilongs.github.io]-[~]
└─$

GRUB_CMDLINE_LINUX 傳遞給所有 Linux 內(nèi)核的公共啟動參數(shù)(包括默認內(nèi)核和恢復(fù)模式內(nèi)核)

┌──[root@liruilongs.github.io]-[~]
└─$vim  /etc/default/grub
 8L, 374B written
┌──[root@liruilongs.github.io]-[~] 
└─$cat /etc/default/grub
GRUB_TIMEOUT=5
GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
GRUB_DEFAULT=saved
GRUB_DISABLE_SUBMENU=true
GRUB_TERMINAL_OUTPUT="console"
GRUB_CMDLINE_LINUX="default_hugepagesz=1G hugepages=10 hugepagesz=1G net.ifnames=0 consoleblank=600 console=tty0 console=ttyS0,115200n8 spectre_v2=off nopti noibrs noibpb selinux=0 crashkern
el=512M"
GRUB_DISABLE_RECOVERY="true"

上面的配置 hugepages=10 hugepagesz=1G,靜態(tài)大頁大小為 1G,數(shù)量為 10

需要說明的是,大頁需要使用連續(xù)的內(nèi)存空間,盡量設(shè)置永久規(guī)則,在開機時分配大頁,如果系統(tǒng)已經(jīng)運行了很久,大量的內(nèi)存碎片,有可能無法分配大頁,因為沒有足夠的連續(xù)內(nèi)存空間。

配置 1G 的靜態(tài)大頁需要CPU 支持,檢查是否包含 pdpe1gb 標簽

┌──[root@liruilongs.github.io]-[~] 
└─$grep pdpe1gb /proc/cpuinfo  
flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_tsc rep_good nopl xtopology no
nstop_tsc cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_s
ingle ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid mpx avx512f avx512dq rdseed adx smap clflushopt clwb avx512cd avx512bw avx512vl xsaveopt xsavec 
xgetbv1 arat avx512_vnni md_clear flush_l1d arch_capabilities
.........................................
┌──[root@liruilongs.github.io]-[~] 
└─$

修改之后使用 grub2-mkconfig 生成了新的 GRUB 配置文件。重啟系統(tǒng)使配置生效。

┌──[root@liruilongs.github.io]-[~] 
└─$grub2-mkconfig -o /boot/grub2/grub.cfg
正在生成 grub 配置文件 ...
找到 Linux 鏡像:/boot/vmlinuz-5.10.0-60.139.0.166.oe2203.x86_64
找到 initrd 鏡像:/boot/initramfs-5.10.0-60.139.0.166.oe2203.x86_64.img
找到 Linux 鏡像:/boot/vmlinuz-5.10.0-60.18.0.50.oe2203.x86_64
找到 initrd 鏡像:/boot/initramfs-5.10.0-60.18.0.50.oe2203.x86_64.img
找到 Linux 鏡像:/boot/vmlinuz-0-rescue-f902bd6553f24605a695d4a876a40b7a
找到 initrd 鏡像:/boot/initramfs-0-rescue-f902bd6553f24605a695d4a876a40b7a.img
Adding boot menu entry for UEFI Firmware Settings ...
完成
┌──[root@liruilongs.github.io]-[~] 
└─$reboot

確認配置,可以看到 Hugepagesize 是1G,但是 nr_hugepages 大小為 5 ,并不是我們配置的 10,這是什么原因,前面我們講,靜態(tài)大頁會直接分配內(nèi)存,即只有配置就會位于常駐內(nèi)存,當(dāng)系統(tǒng)內(nèi)存沒有配置的靜態(tài)大頁大時,系統(tǒng)會自動減少

┌──[root@liruilongs.github.io]-[~] 
└─$cat /proc/meminfo | grep Hug
AnonHugePages:    131072 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       5
HugePages_Free:        5
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:         5242880 kB
┌──[root@liruilongs.github.io]-[~] 
└─$sysctl -a | grep huge
vm.hugepage_mig_noalloc = 0
vm.hugepage_nocache_copy = 0
vm.hugepage_pmem_allocall = 0
vm.hugetlb_shm_group = 0
vm.nr_hugepages = 5
vm.nr_hugepages_mempolicy = 5
vm.nr_overcommit_hugepages = 0
┌──[root@liruilongs.github.io]-[~] 
└─$

我們可以使用 free 命令查看內(nèi)存使用情況驗證這一點

┌──[root@liruilongs.github.io]-[~] 
└─$free -g
               total        used        free      shared  buff/cache   available
Mem:               7           5           0           0           0           1
Swap:              0           0           0

通過臨時修改內(nèi)核參數(shù)調(diào)整靜態(tài)大頁數(shù)目(實際調(diào)整需要考慮靜態(tài)大頁是否使用)

┌──[root@liruilongs.github.io]-[~] 
└─$sysctl -w vm.nr_hugepages=2
vm.nr_hugepages = 2
┌──[root@liruilongs.github.io]-[~] 
└─$sysctl -a | grep nr_hug
vm.nr_hugepages = 2
vm.nr_hugepages_mempolicy = 2
┌──[root@liruilongs.github.io]-[~] 
└─$cat /proc/meminfo | grep Hug
AnonHugePages:    169984 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:       2
HugePages_Free:        2
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:         2097152 kB

確認配置是否生效

┌──[root@liruilongs.github.io]-[~] 
└─$free -g
               total        used        free      shared  buff/cache   available
Mem:               7           2           3           0           0           4
Swap:              0           0           0
┌──[root@liruilongs.github.io]-[~] 
└─$

為了讓進程可以使用大頁,進程必須進行系統(tǒng)函數(shù)調(diào)用,可以調(diào)用 mmap() 函數(shù),或者 shmat() 函數(shù),又或者是 shmget()函數(shù)。如果進程使用的是 mmap()系統(tǒng)函數(shù)調(diào)用,則必須掛載-個 hugetlbfs 文件系統(tǒng)。

┌──[root@liruilongs.github.io]-[~]
└─$mkdir /largepage
┌──[root@liruilongs.github.io]-[~]
└─$mount -t hugetlbfs none /largepage

如果在 NUMA 系統(tǒng)上,內(nèi)核將大頁劃分到所有 NUMA 節(jié)點上,對應(yīng)的靜態(tài)大頁參數(shù)需要分別設(shè)置,而不用設(shè)置全局參數(shù)

┌──[root@liruilongs.github.io]-[~]
└─$cat /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
50
┌──[root@liruilongs.github.io]-[~]
└─$echo 20 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
┌──[root@liruilongs.github.io]-[~]
└─$cat /sys/devices/system/node/node0/meminfo
Node 0 MemTotal:       16082492 kB
Node 0 MemFree:        14969744 kB
Node 0 MemUsed:         1112748 kB
Node 0 SwapCached:            0 kB
Node 0 Active:           562104 kB
Node 0 Inactive:         215520 kB
Node 0 Active(anon):     369388 kB
Node 0 Inactive(anon):        0 kB
Node 0 Active(file):     192716 kB
Node 0 Inactive(file):   215520 kB
Node 0 Unevictable:           0 kB
Node 0 Mlocked:               0 kB
Node 0 Dirty:             28140 kB
Node 0 Writeback:             0 kB
Node 0 FilePages:        420444 kB
Node 0 Mapped:            93924 kB
Node 0 AnonPages:        356560 kB
Node 0 Shmem:             12208 kB
Node 0 KernelStack:        9744 kB
Node 0 PageTables:         6216 kB
Node 0 SecPageTables:         0 kB
Node 0 NFS_Unstable:          0 kB
Node 0 Bounce:                0 kB
Node 0 WritebackTmp:          0 kB
Node 0 KReclaimable:      45436 kB
Node 0 Slab:             111576 kB
Node 0 SReclaimable:      45436 kB
Node 0 SUnreclaim:        66140 kB
Node 0 AnonHugePages:    167936 kB
Node 0 ShmemHugePages:        0 kB
Node 0 ShmemPmdMapped:        0 kB
Node 0 FileHugePages:        0 kB
Node 0 FilePmdMapped:        0 kB
Node 0 Unaccepted:            0 kB
Node 0 HugePages_Total:    20
Node 0 HugePages_Free:     20
Node 0 HugePages_Surp:      0
┌──[root@liruilongs.github.io]-[~]
└─$

透明大頁 vs 靜態(tài)大頁簡單比較

特性

透明大頁(THP)

靜態(tài)大頁(Huge Pages)

配置方式

內(nèi)核自動管理,無需用戶干預(yù)。

需手動預(yù)留(如通過 /etc/default/grub)。

適用場景

通用型應(yīng)用(如 Java、Web 服務(wù))。

高性能計算、數(shù)據(jù)庫(如 Oracle、MySQL)。

內(nèi)存碎片化

可能因頻繁合并/拆分導(dǎo)致碎片。

預(yù)留固定內(nèi)存,無碎片問題。

性能穩(wěn)定性

可能因動態(tài)合并產(chǎn)生性能波動。

性能更穩(wěn)定可控。


責(zé)任編輯:武曉燕 來源: 山河已無恙
相關(guān)推薦

2020-08-10 17:49:25

JVM內(nèi)存溢出

2018-03-16 14:04:45

Linux大內(nèi)存頁虛擬內(nèi)存管理

2020-12-15 08:54:06

Linux內(nèi)存碎片化

2025-04-07 04:20:00

Linux操作系統(tǒng)內(nèi)存管理

2010-09-26 10:53:00

JVM內(nèi)存調(diào)優(yōu)設(shè)置

2023-11-28 08:43:48

2014-12-19 11:07:40

Java

2019-07-17 15:45:24

Spark內(nèi)存Java

2010-09-25 15:52:27

JVM內(nèi)存JVM

2021-04-30 20:20:36

HugePages大內(nèi)存頁系統(tǒng)

2018-08-09 16:32:49

內(nèi)存管理框架

2024-08-02 16:25:10

2013-10-11 17:32:18

Linux運維內(nèi)存管理

2025-03-25 08:20:00

Linux虛擬內(nèi)存系統(tǒng)

2013-03-20 17:18:07

Linux系統(tǒng)性能調(diào)優(yōu)

2025-03-25 01:00:00

2023-02-10 09:28:23

優(yōu)化工具

2023-05-29 07:43:32

JVM內(nèi)存調(diào)優(yōu)

2021-12-09 08:09:31

Linux內(nèi)核臟頁

2022-12-26 14:41:38

Linux內(nèi)存
點贊
收藏

51CTO技術(shù)棧公眾號