無靜態型別系統的動態借用檢查:執行期 Borrow Checker 的設計與實作
scattered-thoughts.net · 2026-04-23
Jamie Brandon 在這篇文章中探索了一個問題:如果不依賴靜態型別系統,能否在動態語言中實現有效的借用檢查?他的答案是肯定的,並提出了一套基於執行期引用計數狀態的動態借用檢查方案。
核心設計:四態引用計數
每個變數維護一個整數引用計數,對應四種不同的語義狀態:
INT_MIN:值已被部分移動(partially moved),不可再存取INT_MIN < count < 0:有|count|個可變借用(borrow)引用正在使用0:可用狀態,可進行借用或共享count > 0:有count個不可變共享(share)引用正在使用
三種引用類型分別以符號表示:移動(^)轉移擁有權並銷毀原變數;借用(!)提供暫時可變存取並在作用域結束時歸還;共享(&)提供不可變存取,允許多個並存。
記憶體布局與檢查開銷
每個引用儲存三個欄位:lease(擁有類型)、lender(借出方變數)、owner(原始擁有者)。作者計算出這些資訊可壓縮至 42 bits(共 16 bytes,使用 20-bit 棧索引定址 8MB 棧的 8-byte 對齊槽位)。絕大多數安全性檢查只需單次整數比較:canBorrow: ref_count == 0、canShare: ref_count >= 0、isMoved: ref_count == INT_MIN。
與 Rust 的比較
此方案與 Rust 的靜態借用檢查的核心差異在於:Rust 在編譯期透過生命週期(lifetime)分析靜態地驗證所有借用規則,此方案則在執行期動態驗證。執行期方案更具彈性(無需生命週期標注),但表達力有所限制——例如不允許將借用引用的生命週期延伸超過出借方變數的作用域。作者坦承:「我對此方案的正確性約有 60% 的把握。」這種誠實的不確定性量化本身就具有參考價值。
錯誤診斷
當規則違反發生時,系統掃描棧以定位問題引用並提供精確的錯誤訊息——相比許多動態語言的模糊崩潰報告,這是顯著的改進。此設計的主要應用場景是嵌入式腳本語言和研究型語言,在這些場景中靜態型別系統的建構成本較高,但記憶體安全性仍是重要需求。
Gecko:具備自動語法錯誤復原的快速 GLR 解析器,每秒解析 200 萬行 C 程式碼
Vladimir Makarov · 2026-04-22
Gecko 是 Vladimir Makarov(GCC 後端開發者)開源的 GLR(Generalized LR)解析器函式庫,主要特點是在接近 YACC 性能的情況下支援模糊文法(ambiguous grammar)並內建自動語法錯誤復原,無需修改文法規則即可處理語法錯誤的輸入。
雙層解析架構
Gecko 採用兩層架構:對於無歧義輸入,使用緊湊的內層迴圈(tight inner loop)在不進行任何額外記憶體配置的情況下解析,與手寫 LALR 解析器的性能幾乎相同;當遇到歧義時,切換至多棧(multi-stack)處理模式,透過「棧合併」(stack merging)機制防止解析狀態的指數級爆炸。解析器使用 SLR(1) 項目集分析文法,並以運算子優先級聲明(operator precedence declarations)解決 shift-reduce 衝突,語義與 YACC 完全相容。
自動錯誤復原機制
Gecko 的錯誤復原不需要文法作者在規則中插入任何錯誤處理標記(與 YACC 的 error 令牌不同)。當語法錯誤發生時,解析器拒絕並彈出失敗的棧,尋找最低成本的復原路徑;要求連續出現的可接受 token 數量(預設為 5 個)作為復原成功的確認門檻,然後在跳過問題 token 後繼續解析。「解析器始終產生對應語法正確輸入的解析樹」是這一機制的設計保證。
性能基準
在真實 C 程式碼的測試中,Gecko 比 YACC 慢 5-12%(儘管能處理 YACC 根本無法解析的模糊文法);比 ElkHound 快 2-2.5 倍,記憶體使用量相當;比 YAEP 快 2-3 倍,記憶體使用量少 3-4 倍。在高度模糊的文法上,Gecko 的性能比競爭實作快約 13 倍,在現代硬體上達到約每秒解析 200 萬行 C 程式碼的吞吐量。整個函式庫約 3,700 SLOC,編譯後約 90KB,通過四個主要 API 呼叫整合。
Nondescript:以 AppleScript 語法啟發的 C 嵌入式單檔腳本語言
GitHub/deadpixi · 2026-04-23
Nondescript 是一個設計用於嵌入 C 應用程式的輕量級腳本語言,定位與 Lua 類似——單檔分發、無外部依賴、可直接編譯進任何 C 專案——但採用了截然不同的語法哲學:從 AppleScript 汲取靈感,設計出接近自然語言的、大小寫不敏感的語法。
技術規格
Nondescript 以 C11 編寫(含 _Alignof 擴充,向下相容 C99),整個實作僅需一個 .c 檔案和一個 .h 檔案,除數學函式庫外無任何標準函式庫依賴。
語法特性
語言的特色語法包含:
- Chunk accessor:
word 1 of myString、item 3 of myList等自然語言式資料存取 - List comprehension:
every character of myString where it != ' '的過濾語法 - Block passing:透過
given區塊傳遞匿名函式 - Scoping:
my關鍵字宣告內層綁定 - Error handling:函式定義中的
on error區塊
C 整合 API
Nondescript 的 C API 採用「槽位式(slot-based)」設計,防止垃圾回收器在 C 程式碼持有引用期間移動物件。API 提供可插拔的記憶體配置器,包括 pool 配置器和 limit 配置器兩種預設實作,便於在記憶體受限環境中使用。C 程式可在執行期動態注冊自定義關鍵字,使語言能夠自然地表達宿主應用程式的領域概念。隨附的示例包含計算機(從 C 呼叫腳本定義的函式)和海龜繪圖(以自然語言指令生成 SVG)兩個展示。
2026 年誰還在使用 jemalloc?主要專案現況調查
The Consensus · 2026-04-16
jemalloc 是由 Jason Evans 為 FreeBSD 開發、後來在 Facebook 工程團隊大規模推廣的高性能記憶體配置器。這篇調查文章追蹤了在 2026 年的技術生態系中,哪些主要軟體專案仍在選用 jemalloc 作為其預設或可選記憶體配置器,以及這些選擇背後的技術理由。
jemalloc 的設計特性
jemalloc 的核心設計針對多執行緒環境的記憶體碎片化問題:採用執行緒本地快取(thread-local cache)減少鎖競爭;以 arena(競技場)結構隔離不同執行緒的配置行為;精細的大小分級(size class)設計降低內部碎片率;以及針對長期運行服務的記憶體還給作業系統(purging)策略。
持續採用 jemalloc 的專案
調查顯示,Firefox、Redis、RocksDB 等知名專案在 2026 年仍選用 jemalloc。Firefox 長期使用 jemalloc 作為其自定義記憶體配置器的基礎,主要因為其在多執行緒瀏覽器架構中的低碎片率表現。Redis 的 jemalloc 整合使其記憶體使用量統計更為精確,並在高負載下維持較低的記憶體碎片率。RocksDB 在處理大量 LSM-tree 寫入操作時,jemalloc 的配置效率有助於維持穩定的延遲特性。
競爭者生態系
調查也梳理了 2026 年記憶體配置器的競爭格局:mimalloc(Microsoft 研究院開發)和 tcmalloc(Google 開發)在部分場景中取代了 jemalloc;Rust 標準函式庫的預設配置器(基於系統 malloc)在許多 Rust 專案中已足夠;而 Linux 核心的 slab/slub 配置器在核心空間繼續主導。jemalloc 在需要精細記憶體碎片控制的長期運行服務中仍保有明確優勢。