newsence
來源篩選

Why is the first C++ (m)allocation always 72 KB?

Hacker News

The author investigates why C++ programs consistently allocate 72 KB at startup and discovers it is for an emergency pool used by libstdc++ to handle exceptions when memory is exhausted.

newsence

為什麼 C++ 的第一次記憶體配置總是 72 KB?

Hacker News
大約 7 小時前

AI 生成摘要

我研究了為什麼 C++ 程式在啟動時總是會配置 72 KB 的記憶體,並發現這是 libstdc++ 為了在記憶體耗盡時仍能處理異常,而預先配置的緊急緩衝池。

背景

在 Linux 環境下開發 C++ 程式時,若使用自定義的記憶體分配器進行追蹤,會發現即便程式碼尚未執行任何邏輯,系統也會固定先分配一塊約 72 KB 的記憶體。這項行為源於 libstdc++ 的異常處理機制,為了確保在系統記憶體耗盡(OOM)的極端情況下仍能拋出異常,標準函式庫會預先配置一塊「緊急緩衝池」(Emergency Pool)作為最後的防線。

社群觀點

針對這項機制,Hacker News 的討論聚焦於實作細節與開發工具的演進。部分開發者對於這塊緩衝池為何不直接採用「靜態分配」提出質疑。他們認為,既然這塊記憶體是為了應對記憶體耗盡的極端狀況,且大小相對固定,若能直接編譯在資料段中,或許能避免啟動時的動態分配開銷。然而,目前的實作允許開發者透過環境變數調整緩衝池大小,甚至能將其完全關閉,這種靈活性可能是選擇動態分配的原因之一。

在技術實作層面,討論串深入探討了如何正確地攔截(Hook)系統的記憶體分配函數。有留言指出,雖然 GNU 曾提供過專門的掛鉤變數,但這些機制在多執行緒環境下並不安全,且在較新版本的 glibc 中已被廢棄。現代且推薦的做法是透過定義並導出自己的分配函數,並利用動態連結器的預載機制來取代標準庫的行為。此外,開發者在撰寫這類底層工具時必須極度謹慎,避免在自定義的分配器內部再次呼叫到會觸發分配的函數,否則將陷入無限遞迴導致崩潰。

關於這 72 KB 帶來的誤解,社群也提到這常讓開發者在進行記憶體洩漏檢測時感到困惑。早期的 Valgrind 會將這塊「仍可觸發」但未釋放的記憶體標記為潛在問題,導致許多人誤以為程式存在漏洞。雖然現代版本的工具已針對此點進行優化,在程式結束時會明確釋放該緩衝池以維持報告的潔淨,但這段歷史仍是許多 C++ 工程師在優化程式時必經的疑惑。

延伸閱讀

  • jsmalloc: 作者在碩士論文期間開發的分配器實作,展示了文中提到的除錯紀錄機制。
  • glibc 原始碼 (elf/dl-minimal-malloc.c): 了解動態連結器在載入 libc 之前如何進行初步的記憶體管理。
  • LD_PRELOAD 教學: 學習如何透過環境變數強制程式載入自定義的共享函式庫。