這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
翻譯原文連結 轉帖/轉載請註明出處
英文原文連結 發表於2014/06/07
記憶體回收機制(Garbage Collection)
Go語言因為強制的記憶體記憶體回收機制變得更加簡單和安全。但這並不意味著記憶體回收機制把Go程式變慢了,或者說記憶體回收機制最終決定了你程式的速度。不可否認,在堆(heap)上分配記憶體是有代價的。每次記憶體回收機制觸發都會消耗一定的CPU。除非記憶體都被釋放了,這些開銷是不可避免的。
但是還有另外一個地方我們可以用來分配記憶體。那就是棧(stack)。
與C語言不同,Go語言不需要你選擇一個變數是分配在堆上(通過malloc),還是棧上(通過將這個變數定義成函數內的局部變數)。Go語言實現了一個叫做逃逸分析(Escape Analysis)的最佳化技術。
逃逸分析能夠判斷是否有任何對函數局部變數的引用在此函數之外也被用到了。如果沒有引用在函數之外被用到,那麼這個局部變數就可以安全地儲存在棧上。在棧上儲存的變數不需要特別的分配和釋放操作。讓我們來看看下面這個例子:
Sum函數把1到100之間的數字相加並返回結果。我們通常不會這麼來寫這個函數,只是用它來展示逃逸分析演算法。
因為numbers變數只在Sum函數裡被引用,編譯器會將這100整數儲存在棧上而不是堆上。所以也就不需要去記憶體回收numbers變數,它會在Sum函數返回的時候自動被釋放掉。
上面顯示的第二個例子也是為了闡述同樣的問題而創造出來的。在CenterCursor函數裡,我們建立了一個新的Cursor結構並且把它的指標儲存在變數c裡。然後我們將變數c傳入Center()函數。Center()函數將Cursor結構平移半個螢幕的距離。最後把Cursor結構的X和Y的座標列印出來。雖然變數c是通過new函數分配的,它不會被儲存在堆上。這是因為變數c的引用並沒有在CenterCursor函數之外被用到。
Go語言的最佳化在預設設定下總是被開啟的。你可以用-gcflags=-m參數來查看編譯器的逃逸分析和內聯決定。
逃逸分析是在編譯時間而不是啟動並執行時候做的。無論記憶體回收機制多麼高效,棧的分配總是比堆的分配要快。接下來,我還會討論到棧。