Go 要違背初心嗎?新提案:手動管理內存
大家好,我是煎魚。
前段 SZ 疫情嚴重的很,公司所在的大廈都被封了 2~3 次...在家中搬磚的我,聽説 Go 要變成 C++ 了?大為震驚。
今天就由煎魚帶大家看看背後的那個提案。
(結果我發這文時,這周直接變成居家辦公 7 天了,車也不能隨便開出去了...)
背景
由於手動管理內存普遍會給程序員帶來一定的心智負擔,提高一門編程語言的入門門檻(還記得大學寫 OC 時經常有同學寫着寫崩了...)。
對應到 Go 語言上,他是一門帶垃圾回收的編程語言。也就是説不需要程序員手動的去管理、釋放程序的內存。

無需手動管理也是 Go 核心開發團隊一直引以為傲的特性之一。
最近有人發起了一個新提案《proposal: arena: new package providing memory arenas》,引起了非常廣泛的討論。
如下圖:

接下來我們將面向該提案進行學習和了解。
新提案
本提案所提到的 Arena,指的是一種從 一個連續的內存區域分配一組內存對象的方式 。優點是 arena 中的對象分配通常比一般的內存分配更有效率,所分配的對象可以一次性釋放,以此達到內存管理或垃圾收集的開銷最小。
其建議在 Go 的標準庫中支持 arena。標準 API 如下:
package arena type Arena struct { // contains filtered or unexported fields } // New allocates a new arena. func New() *Arena // Free frees the arena (and all objects allocated from the arena) so that // memory backing the arena can be reused fairly quickly without garbage // collection overhead. Applications must not call any method on this // arena after it has been freed. func (a *Arena) Free() // New allocates an object from arena a. If the concrete type of objPtr is // a pointer to a pointer to type T (**T), New allocates an object of type // T and stores a pointer to the object in *objPtr. The object must not // be accessed after arena a is freed. func (a *Arena) New(objPtr interface{}) // NewSlice allocates a slice from arena a. If the concrete type of slicePtr // is *[]T, NewSlice creates a slice of element type T with the specified // capacity whose backing store is from the arena a and stores it in // *slicePtr. The length of the slice is set to the capacity. The slice must // not be accessed after arena a is freed. func (a *Arena) NewSlice(slicePtr interface{}, cap int)
這一實踐已經在 Google 得到了應用,且在一些大型應用程序中節省了高達 15% 的CPU和內存使用,這主要是由於減少了垃圾收集的CPU時間和堆內存使用所帶來的效果。
arena 若成為標準庫的使用的例子:
import ( “arena” … ) type T struct { val int } func main() { a := arena.New() var ptrT *T a.New(&ptrT) ptrT.val = 1 var sliceT []T a.NewSlice(&sliceT, 100) sliceT[99].val = 4 a.Free() }
手動調用 arena.New
方法分配 arena 內存,再調用 Free
方法進行釋放。
當然,一般提案中所提到的 arena 並不會在一門帶垃圾回收的編程語言中實現。因為會操作到內存就有可能會不安全,不符合帶垃圾回收的語言定義。
該庫底層採取了動態檢查來確保 arena 釋放內存的操作是安全的。若出現異常情況,就會終止釋放。
爭論
圍繞這這個新的提案,評論區的網友們爭議的非常多。有的會疑惑,為什麼一定要放在標準庫,放第三方庫不行嗎?
實際上在第三方庫中很難安全地做到這一點,因為一個在 arena 庫中分配的變量,他包含指向外部的內存指針,要確保性能下讓 GC 知道他,否則可能會導致錯誤的釋放。

當然,也有人提出,這 Go 就變成像 C++ 一樣,忘記 free、重複 free、提前 free,與 Go 原先標榜的簡潔相差甚遠。
總結
現階段該提案還在積極探討的階段,原型代碼也已經提交《runtime: prototype CL showing possible implementation of arenas》有興趣的小夥伴可以抽時間看看。
這個提案爭議較大,你很難説他是一個庫,還是一個語言的根本性變更。你一旦在原生標準庫支持了,其他關聯的也必然會支持其 API,自然而然就植入進去了,與 “unsafe” 標準庫定位一致,都是不安全的因素。
大家怎麼看?以後是不是可以玩出新的花樣了...
關注煎魚,獲取業內第一手消息和知識 :point_down:
你好,我是煎魚, 出版過 Go 暢銷書《Go 語言編程之旅》,再到獲得 GOP(Go 領域最有觀點專家)榮譽, 點擊藍字查看我的出書之路 。
日常分享高質量文章,輸出 Go 面試、工作經驗、架構設計, 加微信拉讀者交流羣,和大家交流!
- Go 代碼風格沒人喜歡?不對,Gofmt 是所有人的最愛...
- 10 張圖解|高併發分佈式架構演進
- Go 只會 if err != nil?這是不對的,分享這些優雅的處理姿勢給你!
- 中美程序員不完全對比
- Go 常量只支持基本數據類型?為什麼?社區撕了 9 年了...
- Go1.19 那些事:國產芯片、內存模型等新特性,你知道多少?
- 有人問你後端面試考哪些?把這篇扔給他!
- Go 內聯優化:如何讓我們的程序更快?
- goto 語句讓 Go 代碼變成意大利麪條?
- Go 錯誤處理中再套個娃,能解決煩惱不?
- 10 條 Go 官方諺語,你知道幾條?
- 新提案:創建 Go 簡單類型的指針表達式
- 為什麼 Go 語言能在中國這麼火?
- 好物分享:快速找到 Goroutine 泄露的地方
- 新提案:增加標準庫 Context 的取消 API
- Go 之父:聊聊我眼中的 Go 語言和環境
- 太瘋狂了,Go 程序説 nil 不是 nil...
- Go 返回值命名還有存在的必要嗎?
- Go 要違背初心嗎?新提案:手動管理內存
- 開啟 Go 泛型時代:第三方泛型庫分享