後端工坊 2026 年 4 月 24 日

2026-04-24 — 後端工坊:動態借用檢查、Gecko GLR 解析器、Nondescript 嵌入式語言、jemalloc 現況

無靜態型別系統的動態借用檢查:執行期 Borrow Chec…

無靜態型別系統的動態借用檢查:執行期 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 == 0canShare: ref_count >= 0isMoved: ref_count == INT_MIN

與 Rust 的比較

此方案與 Rust 的靜態借用檢查的核心差異在於:Rust 在編譯期透過生命週期(lifetime)分析靜態地驗證所有借用規則,此方案則在執行期動態驗證。執行期方案更具彈性(無需生命週期標注),但表達力有所限制——例如不允許將借用引用的生命週期延伸超過出借方變數的作用域。作者坦承:「我對此方案的正確性約有 60% 的把握。」這種誠實的不確定性量化本身就具有參考價值。

錯誤診斷

當規則違反發生時,系統掃描棧以定位問題引用並提供精確的錯誤訊息——相比許多動態語言的模糊崩潰報告,這是顯著的改進。此設計的主要應用場景是嵌入式腳本語言和研究型語言,在這些場景中靜態型別系統的建構成本較高,但記憶體安全性仍是重要需求。

原始來源:scattered-thoughts.net


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 呼叫整合。

原始來源:vnmakarov.github.ioGitHub/gecko


Nondescript:以 AppleScript 語法啟發的 C 嵌入式單檔腳本語言

GitHub/deadpixi · 2026-04-23

Nondescript 是一個設計用於嵌入 C 應用程式的輕量級腳本語言,定位與 Lua 類似——單檔分發、無外部依賴、可直接編譯進任何 C 專案——但採用了截然不同的語法哲學:從 AppleScript 汲取靈感,設計出接近自然語言的、大小寫不敏感的語法。

技術規格

Nondescript 以 C11 編寫(含 _Alignof 擴充,向下相容 C99),整個實作僅需一個 .c 檔案和一個 .h 檔案,除數學函式庫外無任何標準函式庫依賴。

語法特性

語言的特色語法包含:

  • Chunk accessorword 1 of myStringitem 3 of myList 等自然語言式資料存取
  • List comprehensionevery character of myString where it != ' ' 的過濾語法
  • Block passing:透過 given 區塊傳遞匿名函式
  • Scopingmy 關鍵字宣告內層綁定
  • Error handling:函式定義中的 on error 區塊

C 整合 API

Nondescript 的 C API 採用「槽位式(slot-based)」設計,防止垃圾回收器在 C 程式碼持有引用期間移動物件。API 提供可插拔的記憶體配置器,包括 pool 配置器和 limit 配置器兩種預設實作,便於在記憶體受限環境中使用。C 程式可在執行期動態注冊自定義關鍵字,使語言能夠自然地表達宿主應用程式的領域概念。隨附的示例包含計算機(從 C 呼叫腳本定義的函式)和海龜繪圖(以自然語言指令生成 SVG)兩個展示。

原始來源:GitHub/deadpixi/nondescript


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 在需要精細記憶體碎片控制的長期運行服務中仍保有明確優勢。

原始來源:The Consensusjemalloc GitHub


End of article
0
Would love your thoughts, please comment.x
()
x