Go 部落格
Go GC:優先考慮低延遲和簡潔性
設定
Go 正在構建一個垃圾收集器(GC),不僅是為了 2015 年,更是為了 2025 年及以後:一個 GC,它支援當今的軟體開發,並隨著新軟體和硬體在未來十年不斷發展而擴充套件。這樣的未來將不再容忍“停止世界”(stop-the-world)的 GC 暫停,而這曾是 Go 等安全語言更廣泛應用的障礙。
Go 1.5 是這個未來的第一個亮點,其 GC 延遲遠低於我們一年前設定的 10 毫秒目標。我們在 Gophercon 的一次演講中展示了一些令人印象深刻的數字。延遲的改進引起了廣泛關注;Robin Verlangen 的部落格文章 《每天數十億次請求遇上 Go 1.5》 用端到端的結果驗證了我們的方向。我們特別喜歡 Alan Shreve 的生產伺服器圖表和他的“天哪,減少 85%”的評論。
如今,16GB RAM 成本為 100 美元,CPU 擁有多個核心,每個核心都有多個硬體執行緒。十年後,這些硬體將顯得陳舊,但今天用 Go 構建的軟體將需要擴充套件以滿足不斷增長的需求和下一個大事件。考慮到硬體將提供提高吞吐量的能力,Go 的垃圾收集器被設計成優先考慮低延遲,並且只能透過一個旋鈕進行調整。Go 1.5 是這條道路上的第一大步,而這些第一步將永遠影響 Go 及其最能支援的應用程式。這篇博文將概述我們為 Go 1.5 收集器所做的工作。
潤飾
為了建立一個面向未來的垃圾收集器,我們回顧了幾十年前的演算法。Go 的新垃圾收集器是一個併發、三色、標記-清除的收集器,這一概念最早由 Dijkstra 於 1978 年提出。這與當今大多數“企業級”垃圾收集器形成了刻意的分歧,並且我們認為它非常適合現代硬體的特性和現代軟體的延遲要求。
在三色收集器中,每個物件要麼是白色、灰色或黑色,我們將堆視為由連線物件組成的圖。GC 週期開始時,所有物件都是白色的。GC 訪問所有根,這些根是應用程式直接可訪問的物件,例如全域性變數和棧上的內容,並將它們標記為灰色。然後,GC 選擇一個灰色物件,將其標記為黑色,然後掃描它以查詢指向其他物件的指標。當掃描發現指向白色物件的指標時,它會將該物件變為灰色。這個過程會重複進行,直到沒有灰色物件為止。此時,白色物件被認為是不可達的,可以被重用。
所有這些都與應用程式(稱為改變器)在收集器執行時更改指標的操作同時進行。因此,改變器必須維護一個不變數,即沒有黑色物件指向白色物件,以免垃圾收集器丟失它已經訪問過的堆部分中的某個物件。維護這個不變數是寫屏障的職責,它是一個小的函式,當堆中的指標被修改時,改變器會執行它。Go 的寫屏障會在指標指向的物件當前是白色時將其變為灰色,從而確保垃圾收集器最終會掃描它以查詢指標。
決定何時完成查詢所有灰色物件的工作是微妙的,並且如果我們要避免阻塞改變器,可能會很昂貴且複雜。為了保持簡單,Go 1.5 會盡可能多地並行執行工作,然後短暫地停止世界(stop-the-world)以檢查所有潛在的灰色物件來源。在這次最終的停止世界所需的時間和此 GC 所完成的總工作量之間找到最佳平衡點是 Go 1.6 的一個主要交付成果。
當然,細節決定成敗。我們何時開始 GC 週期?我們使用什麼指標來做這個決定?GC 應如何與 Go 排程程式互動?我們如何暫停改變器執行緒足夠長的時間來掃描其堆疊?我們如何表示白色、灰色和黑色,以便我們能夠有效地查詢和掃描灰色物件?我們如何知道根在哪裡?我們如何知道物件中的指標在哪裡?我們如何最小化記憶體碎片?我們如何處理快取效能問題?堆應該有多大?等等,有些與分配有關,有些與查詢可達物件有關,有些與排程有關,但很多都與效能有關。這些領域的低階討論超出了本博文的範圍。
從更高層次來看,解決效能問題的一種方法是新增 GC 旋鈕,每個旋鈕對應一個性能問題。然後,程式設計師可以調整這些旋鈕,為他們的應用程式尋找合適的設定。缺點是,經過十年,每年增加一兩個新旋鈕,最終會催生《GC 旋鈕調整員就業法》。Go 不會走這條路。相反,我們提供了一個名為 GOGC 的單一旋鈕。此值控制堆的總大小相對於可達物件的大小。預設值 100 表示堆的總大小現在比上一個收集週期後可達物件的大小大 100%(即兩倍)。200 表示堆的總大小比可達物件的大小大 200%(即三倍)。如果您想減少 GC 所花費的總時間,請增加 GOGC。如果您想用更多的 GC 時間換取更少的記憶體,請降低 GOGC。
更重要的是,隨著下一代硬體 RAM 翻倍,簡單地將 GOGC 翻倍將使 GC 週期數量減半。另一方面,由於 GOGC 基於可達物件的大小,加倍負載(透過使可達物件加倍)無需重新調整。應用程式會自動擴充套件。此外,由於不受支援數十個旋鈕的負擔,執行時團隊可以專注於根據真實客戶應用程式的反饋來改進執行時。
要點
Go 1.5 的 GC 預示著一個未來,在這個未來中,“停止世界”的暫停不再是遷移到安全語言的障礙。這是一個應用程式可以輕鬆隨硬體擴充套件的未來,並且隨著硬體變得越來越強大,GC 將不會阻礙更好、更具可擴充套件性的軟體。這是未來十年及以後一個不錯的發展方向。有關 1.5 GC 的更多詳細資訊以及我們如何消除延遲問題,請參閱 “Go GC:延遲問題已解決”簡報或幻燈片。
下一篇文章:Golang UK 2015
上一篇文章:Go 1.5 釋出
部落格索引