瞭解 Golang 中的內存管理:Stack vs Heap
內存管理是編程的一個重要方面,瞭解內存管理的工作原理會極大地影響應用程序的性能和效率。在 Golang 中,內存分配主要通過兩個區域進行管理:棧和堆。在本文中,我們將探討堆棧和堆內存的區別、Golang 如何處理這些分配,並提供實際示例來說明這些概念。
Stack
堆棧是什麼?
堆棧是以後進先出(LIFO)方式運行的內存區域。它用於存儲局部變量和函數調用信息,如返回地址、參數和局部變量。堆棧因其後進先出的性質而非常高效,可以快速分配和取消分配內存。
堆棧內存的特點
-
基本內存類型:堆棧是用於 goroutine 內局部變量的基本內存類型。
-
後進先出(Last-In, First-Out):堆棧以後進先出方式運行,即最後分配的內存最先被去分配。
-
局部變量:goroutine 中的所有局部變量都存儲在堆棧中。
-
初始分配:當一個程序啓動時,會爲其堆棧分配一個連續的 2KB 內存空間。
-
動態大小:堆棧可在執行過程中增大或縮小,但仍保持連續以確保數據的本地性。
-
自動清理當函數返回時,堆棧內存會自動清理,因此非常高效。
Heap
什麼是 "堆"?
堆是用於動態內存分配的內存區域。與堆棧不同,堆上的內存不是自動管理的,需要手動分配和刪除。堆適用於需要在函數調用範圍之外持續存在的變量或大型數據結構。
堆內存的特點
-
共享內存池:堆是所有程序都能訪問的共享內存池。
-
分配條件:如果編譯器無法證明某個變量在函數返回後不會被引用,就會在堆上分配該變量。
-
垃圾回收:堆內存由垃圾收集器(GC)管理,它會自動回收不再使用的內存。
-
性能影響:垃圾回收器在運行時會消耗大約 25% 的 CPU 可用容量。
-
尺寸更大:堆通常比棧大,因此適合分配大型對象或數據結構。
-
訪問速度較慢:由於動態內存管理的開銷和潛在的緩存問題,訪問堆內存的速度比棧內存慢。
棧與堆主要區別
生命週期
-
堆棧變量的壽命很短,只存在於函數調用中。
-
堆變量可以在函數範圍之外持續存在。
內存大小
-
堆棧:大小有限,大量分配時容易溢出。
-
堆:容量更大,可處理更大的數據結構。
性能
-
堆棧:由於採用後進先出方式訪問,且靠近 CPU,因此速度更快
-
堆:由於動態分配和垃圾回收的開銷,速度較慢。
管理
-
堆棧:由編譯器自動管理。
-
堆:在垃圾回收的幫助下人工進行管理。
清理:
-
堆棧:函數返回時自動清理。
-
堆:由垃圾回收器清理,會影響性能。
Golang 中的內存管理
Golang 的內存管理設計得既高效又方便開發者。Go 運行時會根據變量的生命週期和大小自動決定是在堆棧還是在堆上分配內存。下面是 Golang 的管理方法:
-
轉義分析:在複雜化過程中,Go 會執行逃逸分析,以確定應在堆棧還是堆上分配變量。如果變量逃出了本地函數的作用域(即在函數返回後被引用),就會在堆上分配。
-
垃圾回收 Go 的垃圾回收器會自動回收不再使用的堆內存,從而減輕了手動內存管理的負擔。
Example: 逃逸分析
func newIntPointer() *int {
x := 42
return &x // 'x' escapes to the heap
}
結論
瞭解堆棧和堆內存之間的區別,以及 Golang 如何處理內存分配,對於編寫高效、高性能的 Go 程序至關重要。棧適用於短期變量和快速訪問,而堆則是較大的持久性數據所必需的。Golang 通過逃逸分析和垃圾回收等技術自動管理內存,幫助開發人員專注於編寫簡潔的代碼,而不必過分擔心內存分配細節。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/BxBcX3gzIqaZfqziSvs1HA