Go 部落格

Go 執行時:四年後

Michael Knyszek
2022 年 9 月 26 日

自 2018 年 關於 Go GC 的上一篇博文以來,Go GC 以及更廣泛的 Go 執行時一直在穩步改進。我們承擔了一些大型專案,這些專案源於真實的 Go 程式和 Go 使用者面臨的實際挑戰。讓我們來回顧一下亮點!

有什麼新功能?

這些更改對使用者來說大部分是不可見的:他們喜歡的 Go 程式碼透過升級 Go 版本就能執行得更好。

一個新配置項

Go 1.19 帶來了一項長期請求的功能,該功能需要一些額外的操作才能使用,但具有巨大的潛力:Go 執行時的軟記憶體限制

多年來,Go GC 只有一個調整引數:GOGCGOGC 允許使用者調整Go GC 造成的 CPU 開銷和記憶體開銷之間的權衡。多年來,這個“配置項”很好地服務了 Go 社群,涵蓋了各種各樣的用例。

Go 執行時團隊一直不願向 Go 執行時新增新的配置項,這並非沒有原因:每一個新的配置項都代表著配置空間中一個新的維度,我們需要對其進行測試和維護,並且可能需要永遠如此。此外,配置項的泛濫也給 Go 開發人員帶來了理解和有效使用它們的負擔,而配置項越多,這種負擔就越重。因此,Go 執行時一直傾向於在最少的配置下也能表現良好。

那麼,為什麼要新增記憶體限制配置項呢?

記憶體不像 CPU 時間那樣可以隨意替換。CPU 時間,如果你稍等片刻,未來總會有更多的。但記憶體是有限的。

記憶體限制解決了兩個問題。

首先,當應用程式的峰值記憶體使用不可預測時,僅靠 GOGC 幾乎無法防止記憶體耗盡。僅使用 GOGC,Go 執行時根本不知道它有多少可用的記憶體。設定記憶體限制可以使執行時能夠應對短暫的、可恢復的負載峰值,因為它知道何時需要更努力地工作以減少記憶體開銷。

其次,為了在不使用記憶體限制的情況下避免記憶體不足錯誤,必須根據峰值記憶體來調整 GOGC,從而導致更高的 GC CPU 開銷以維持較低的記憶體開銷,即使在應用程式未達到峰值記憶體使用且有大量記憶體可用時也是如此。這在我們容器化的世界中尤其重要,程式被放置在具有特定和隔離記憶體限制的盒子中;我們應該充分利用它們!透過提供應對負載峰值的保護,設定記憶體限制可以使 GOGC 在 CPU 開銷方面進行更積極的調整。

記憶體限制的設計易於採用且健壯。例如,它限制的是應用程式 Go 部分的整體記憶體佔用,而不僅僅是 Go 堆,因此使用者不必擔心計算 Go 執行時的開銷。執行時還會根據記憶體限制調整其記憶體回收策略,從而更積極地響應記憶體壓力,將記憶體歸還給作業系統。

但是,雖然記憶體限制是一個強大的工具,但仍需謹慎使用。一個主要的警告是,它可能會使你的程式面臨 GC 抖動:即程式花費過多時間執行 GC,導致無法進行有意義的進展。例如,如果記憶體限制設定得太低,不足以滿足程式實際需要的記憶體量,Go 程式可能會出現抖動。這在以前不太可能發生,除非 GOGC 被明確地大大傾向於記憶體使用。我們選擇優先耗盡記憶體而不是出現抖動,因此作為一種緩解措施,執行時會將 GC 限制在總 CPU 時間的 50%,即使這意味著超過記憶體限制。

所有這些都需要仔細考慮,因此作為這項工作的一部分,我們釋出了一個全新的 GC 指南,其中包含互動式視覺化,幫助您理解 GC 的成本以及如何對其進行調整。

結論

試試記憶體限制!在生產環境中使用它!閱讀GC 指南

我們一直在尋求關於如何改進 Go 的反饋,同時也很樂意聽到它對您來說就是好用的情況。給我們傳送反饋

下一篇文章:Go 的十三年
上一篇文章:2022 年第二季度 Go 開發者調查結果
部落格索引