Linux 7.2 計畫引入匿名記憶體的 mTHP 自動建立機制
LWN.net · 2026-06-11
Linux 7.2 開發週期正在審議一項記憶體管理新功能:讓核心在頁面錯誤(page fault)時自動為匿名映射選擇合適的多尺寸透明大頁(multi-size Transparent Huge Pages,mTHP),無需應用程式主動呼叫 madvise(MADV_HUGEPAGE) 或全域開啟 always 模式。此提案由記憶體管理社群在 2026 年 6 月上旬提出,旨在彌補現有 khugepaged 背景折疊路徑無法涵蓋中間尺寸頁面的空缺。
背景
透明大頁(THP)自 Linux 2.6.38 引入,傳統上以 PMD 粒度(2 MB)為主,對記憶體碎片化程度較高的系統不夠友好。從 6.6 版本起,核心逐步充實了 mTHP 支援,可透過 /sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled 個別啟用 16K、32K、64K 等中間尺寸,或使用開機參數 thp_anon=16K-64K:always 批次設定。這些頁面以 PTE 方式映射,不佔用 PMD 入口,因此在記憶體碎片較多的場景仍能順利分配。
相較於基礎頁(4 KB),mTHP 可將頁面錯誤次數降低 4 至 16 倍;相較於 2 MB 大頁,每次錯誤需清零的記憶體量大幅縮小,延遲尖峰因此降低。部分架構(如 arm64 的 Contiguous PTE)還能對連續對齊的 PTE 進行 TLB 壓縮,進一步提升轉譯效率。現有的統計資料可透過 /sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/stats 中的計數器查閱,包括 anon_fault_alloc、anon_fault_fallback、swpout 等。
核心改動
現有架構下,mTHP 的觸發仍依賴全域 always 模式或 madvise 應用程式提示;khugepaged 背景折疊路徑的範圍亦一向僅限 PMD 尺寸的 2 MB 頁面。7.2 計畫新增的自動建立路徑讓核心在頁面錯誤處理期間,依據當前工作集大小與可用連續記憶體動態決定是否提升至較大的 mTHP 尺寸,而無須等待背景掃描或應用程式提示。
配置層面,defer 與 defer+madvise 模式讓核心在背景喚醒 kswapd 進行回收、喚醒 kcompactd 進行壓縮,避免在分配時直接阻塞應用程式。開機參數支援範圍與優先級語法,例如 thp_anon=16K-64K:always;256K:madvise;2M:never;文件明確指出若 thp_anon= 曾出現於命令列,所有未明確設定的尺寸將隱式設為 never,確保行為可預期。
影響範圍
此功能主要影響匿名記憶體場景,包含 malloc 分配的堆積空間與執行緒堆疊。對多執行緒伺服器應用程式而言,頁面錯誤次數的減少可直接改善首次存取延遲(first-touch latency),特別是大量分配小物件但存取模式相對集中的場景,如 HTTP 請求處理或 RPC 框架的 arena 分配。
- sysfs 設定路徑:
/sys/kernel/mm/transparent_hugepage/hugepages-<size>kB/enabled - 開機參數語法:
thp_anon=16K-64K:always;256K:madvise;2M:never - 監控計數器:
anon_fault_alloc、anon_fault_fallback、swpout
發行版維護者需注意,若系統記憶體本就吃緊,自動提升至較大 mTHP 尺寸可能增加 fallback 頻率。建議透過 thp_anon 明確限定啟用範圍,以兼顧效能與穩定性。
原始來源:LWN.net — Automatic mTHP creation in 7.2;核心文件:kernel.org — Transparent Hugepage Support
Rust 的 main 之前:用連結器區段與建構函式實現零成本初始化
grack.com (Matt Mastracci) · 2026-06-11
大多數 Rust 開發者認為程式從 main() 開始執行,但實際上在此之前已有一層完整的初始化機制在運作。grack.com 作者 Matt Mastracci 於 2026 年 6 月 11 日發表深度技術文章,系統性拆解 Rust 執行時在進入 main 之前的工作,並示範如何利用連結器區段(linker sections)與建構函式(constructors)實現跨模組的依賴注入與靜態資料初始化。
背景
每個程式語言都有自己的執行時層,負責橋接應用程式碼與作業系統。Rust 的執行時建構在 C 執行時(libc)之上,處理 panic 基礎設施、執行緒本地儲存(TLS)以及將 C 風格程式參數轉換為 Rust 的 std::env::args。在 Linux 上,ELF 標頭的 e_entry 欄位指向 _start 符號;在 Windows 上則對應 _WinMainCRTStartup。
建構函式的概念源自 GCC 的 __attribute__((constructor)),允許程式碼在 main 之前自動執行,無需明確呼叫鏈。GNU 工具鏈的連結器會為任何 C 相容名稱的區段自動合成 __start_SECTION 與 __stop_SECTION 符號,標示區段的起始與結束位址。文章特別澄清一個常見誤解:連結器設定的是符號的地址,而非指標的值,這兩者在程式碼層面容易混淆,但理解此差異是正確使用連結器區段的前提。
核心改動
文章展示了三種實際應用場景。首先是跨模組依賴注入:CLI 子命令可在各自的定義處透過連結器區段「自我登記」,消費端在執行時讀取聚合後的資料,無需集中維護命令列表,達到低耦合設計。其次是在 main 啟動前安全地修改靜態資料——pre-main 階段仍是單執行緒環境,搭配 UnsafeCell 或 SyncUnsafeCell 包裝,並確保所有修改在主執行緒啟動額外執行緒之前完成,即可不使用鎖完成全域狀態初始化。第三個場景是編譯期字串池(string interning),利用連結時聚合建構零分配、可排序的靜態字串集合。
use std::cell::SyncUnsafeCell;
static DATA: SyncUnsafeCell<Vec<u32>> = SyncUnsafeCell::new(Vec::new());
#[ctor::ctor]
unsafe fn init() {
// pre-main:單執行緒,安全修改靜態資料
(*DATA.get()).push(42);
}
作者推薦的工具鏈涵蓋四個 crate:ctor(跨平台建構函式巨集,最新版 link-section-0.18.2,發布於 2026-06-06)、link-section(型別安全的連結器區段抽象)、scattered-collect(連結時聚合的高階集合),以及 inventory 與 linkme(提供不同取捨的替代方案)。
影響範圍
這些技術在需要高度模組化、零啟動開銷的場景特別適用,例如外掛架構、嵌入式系統的驅動程式自動探測,或不允許動態分配的環境。文章也誠實列出限制:建構函式內不可 panic、標準函式庫在 pre-main 階段可用性有限、同優先級的初始化順序因平台而異,且 WASM 的自訂區段無法被程式碼讀取,需要額外處理。
死碼消除(dead code elimination)在連結器區段模式下面臨挑戰:若定義提供者的目標檔案未被正常連結,其區段貢獻會被靜默丟棄。Miri 與部分 sanitizer 對 pre-main 程式碼的支援目前也尚不完整。整體而言,這套技術提供了一條不依賴動態登記表、編譯期確定性強的初始化路徑,是 Rust 生態中鮮少被系統性記錄的底層能力。
根本不需要擴展:Harper 語法檢查器的 Local-First 架構實戰
elijahpotter.dev (Elijah Potter) · 2026-06-12
當一款軟體登上 Hacker News 首頁並引爆流量,伺服器端應用程式的工程師通常會緊盯監控面板、擴充容量。但 Harper 語法檢查器的作者 Elijah Potter 卻是隔天早上瀏覽 Hacker News 時才意識到流量暴增,整個過程毫無中斷。原因很簡單:Harper 的語法分析完全在使用者裝置上執行,伺服器本就沒有需要擴展的東西。
原本的問題
Harper 是一款開源語法檢查工具,以 Rust 撰寫的 harper-core 為核心,對外提供 harper.js(JavaScript 綁定)與 harper-ls(語言伺服器協定)。它整合於 VS Code、Neovim、Obsidian、Zed 等編輯器,以及 Chrome 與 Firefox 擴充套件。所有語法分析均在本地完成,延遲低於 10 毫秒,且完全不傳送資料至任何伺服器,由 Automattic 以 Apache-2.0 授權開源維護。
Potter 以 LanguageTool 作為對照組。LanguageTool 採用典型的伺服器端架構,使用者的文字需傳送至後端處理,流量激增時需要雲端架構師介入、提高 AWS 帳單。這種「先建立服務,再隨流量擴展」的模式被 Potter 視為一種必要之惡,而非值得追求的設計目標。
採用的方法
Local-first(或稱 edge-first)架構的核心是讓運算盡可能在靠近使用者的地方執行。對 Harper 而言,這意味著語法規則引擎、詞典查詢、拼字糾正全部打包進客戶端的二進位檔或 WebAssembly 模組,而非透過網路呼叫遠端 API。Potter 的文章點出了一個工程討論中常被忽視的架構選擇:不需要擴展,遠比擅長擴展更有價值。
這種架構的代價是較高的客戶端資源消耗,以及版本更新的分發挑戰——使用者端的規則庫與邏輯需要隨應用程式一起更新,而非在伺服器端統一部署。Harper 透過輕量化設計(低 CPU、低記憶體佔用)降低客戶端負擔,並依托各平台的套件管理與擴充套件更新機制解決版本分發問題。
實際效果
Potter 的案例直接挑戰了「能擴展才是好架構」的預設框架。當系統的運算需求不隨使用者數量線性增長,「水平擴展能力」這個指標就失去意義。對語法檢查、本地搜尋、離線優先資料同步等任務,local-first 架構可將雲端基礎設施成本降至接近零,同時消除網路延遲帶來的使用者體驗波動。
這篇文章也間接反映了 WebAssembly 生態成熟的背景——Rust 程式碼可以無縫編譯為 WASM 並嵌入瀏覽器擴充套件或網頁應用,讓過去只能在伺服器端執行的語言處理邏輯下沉至客戶端。Harper 的案例提供了一個具體的參照點:在適合的問題領域,選擇不建伺服器本身就是一種架構決策,往往比精心設計的分散式系統更易維護、更省成本。
原始來源:elijahpotter.dev — Local-First Software Is Easier to Scale