go語言,局部變數什麼時候回收?

code如圖。變數vec和j,第一次回收時機是啥?如果是等到下一次gc才處理,那麼要寫出gc友好的代碼,局部變數申請都要做到盡量少的好了。特別是循環申明很多次的這個j。哪位看懂gc相關源碼的同學(或者通過其他途徑了解)來解釋下?

能順帶全面解釋一下,go語境下怎麼做到gc友好,就更好了了~


Go 有 escape analysis, 在編譯期,它會分析你的變數是否在函數執行完畢那一刻,程序有沒有可能有別的對象引用到它(所謂逃逸),如果沒有,那這個變數就可以在棧上分配,完全不經過 gc. 如果它已經逃逸了,那什麼時候 gc 就由不得你了。

在 go build 時加上 -gcflags=-m 參數,它會在編譯時列印什麼東西 escape 了,題主的程序,不好意思,全部中招:

./test.go:16: j escapes to heap
./test.go:18: vec escapes to heap
./test.go:12: make([]int, 5, 5) escapes to heap

原因其實在 fmt.Println, 你看文檔,fmt.Println 接收的是 interface{}... Interface 實際上就是個數據指針+itable指針(http://research.swtch.com/interfaces),然後編譯器就已經瞎了。所以就只好判斷,這時候 j 和 vec 都 escape 了……(叫你不加 generic……)另外注意雖然這時傳給 fmt.Println 的 interface{} 並不指向 j, 而是一個 j 的拷貝,但因為編譯器已經傻掉,這個拷貝只能放堆上,所以這個 escape 也算在 j 頭上了。

伺候 Go gc 最簡單的就是少把指針傳來傳去少弄點零碎共享對象。除了顯式指針外 interface{} 是個指針,slice 是個指針 blah blah blah. 沒有顯著理由優先複製傳值而不是傳指針,在現代機器上,複製結構往往很廉價(Go 沒有複製構造函數之類的東東複製還真就是個 memory copy)。

當然最重要的,做 profiling, 找到真正要優化的點,之後像上面這種靜態分析工具也能幫大忙。

大推薦 Go 核心開發者 Russ Cox 的兩篇 Go data structures

http://research.swtch.com/godata

http://research.swtch.com/interfaces


推薦閱讀:

Go語言為什麼在大陸特別火?
如何看待 Golang 用首字母的大小寫來確定訪問許可權?
為何 Go 依然遠遠沒有 Python 流行?
為什麼負數的取余計算各個編程語言結果不統一?
現在的編程語言已經泛濫了,為什麼google還要推出GO語言?

TAG:編程語言 | 編程 | Go語言 |