Go語言之GO 語言變數逃逸分析

2022-09-07 07:54:10 字數 2467 閱讀 9353

棧只允許從線性表的同一端放入和取出資料,按照後進先出(lifo,last infirst out)的順序

棧的特點:

棧可用於記憶體分配,棧的分配和**速度非常快

func calc(a, b int) int
go語言預設情況下會將 c 和 x 分配在棧上,這兩個變數在 calc() 函式退出時就不再使用,函式結束時,儲存 c 和 x 的棧記憶體再出棧釋放記憶體,整個分配記憶體的過程通過棧的分配和**都會非常迅速。

堆分配記憶體和棧分配記憶體相比,堆適合不可預知大小的記憶體分配。但是為此付出的代價是分配速度較慢,而且會形成記憶體碎片。

——自動決定變數分配方式,提高執行效率

在c語言中需要手動進行記憶體分配,例如區域性變數可以分配棧,全域性變數或者結構體可以分配堆。

go語言將這個過程整合到了編譯器中,命名為「變數逃逸分析」。通過編譯器分析**的特徵和**的生命週期,決定應該使用堆還是棧來進行記憶體分配。

通過下面的**來展現go語言如何使用命令列來分析變數逃逸,

package main

import "fmt"

func dummy(b int) int

func void()

func main()

-------------------------------------------

dummy() 函式擁有乙個引數,返回乙個整型值,用來測試函式引數和返回值分析情況。

宣告變數 c,用於演示函式臨時變數通過函式返回值返回後的情況。

這是乙個空函式,測試沒有任何引數函式的分析情況。

在 main() 中宣告變數 a,測試 main() 中變數的分析情況。

呼叫 void() 函式,沒有返回值,測試 void() 呼叫後的分析情況。

列印 a 和 dummy(0) 的返回值,測試函式返回值沒有變數接收時的分析情況。

go run -gcflags "-m -l" main.go
使用 go run 執行程式時,-gcflags 引數是編譯引數。其中 -m 表示進行記憶體分配分析,-l 表示避免程式內聯,也就是避免進行程式優化。

ps d:\goprogram\go\src\day05> go run -gcflags "-m -l" .\lianxi.go

# command-line-arguments

.\lianxi.go:21:13: main ... argument does not escape

.\lianxi.go:21:13: a escapes to heap

.\lianxi.go:21:22: dummy(0) escapes to heap

0 0

執行結果分析

第 2 行告知「**的第 13 行的變數 a 逃逸到堆」。

第 3 行告知「dummy(0) 呼叫逃逸到堆」。由於 dummy() 函式會返回乙個整型值,這個值被 fmt.println 使用後還是會在 main() 函式中繼續存在。

第 4 行,這句提示是預設的,可以忽略。

上面例子中變數 c 是整型,其值通過 dummy() 的返回值「逃出」了 dummy() 函式。變數 c 的值被複製並作為 dummy() 函式的返回值返回,即使變數 c 在 dummy() 函式中分配的記憶體被釋放,也不會影響 main() 中使用 dummy() 返回的值。變數 c 使用棧分配不會影響結果。

package main

import "fmt"

// 宣告空結構體測試結構體逃逸情況

type data struct

func dummy() *data

func main()

執行過程

go run -gcflags "-m -l" main.go

# command-line-arguments

./main.go:15:9: &c escapes to heap

./main.go:12:6: moved to heap: c

./main.go:20:19: dummy() escapes to heap

./main.go:20:13: main ... argument does not escape

&{}

go語言最終選擇將 c 的 data 結構分配在堆上。然後由垃圾**器去** c 的記憶體。

在使用go語言進行程式設計時,go語言的設計者不希望開發者將精力放在記憶體應該分配在棧還是堆的問題上,編譯器會自動幫助開發者完成這個糾結的選擇,但變數逃逸分析也是需要了解的乙個編譯器技術,這個技術不僅用於go語言,在 j**a編譯器覺得變數應該分配在堆和棧上的原則是:

Go語言之GO 語言常量

相對於變數,常量是恆定不變的值,多用於定義程式執行期間不會改變的那些值。常量的宣告和變數宣告非常類似,只是把var換成了const,常量在定義的時候必須賦值。const pi 3.1415 const e 2.7182宣告了pi和e這兩個常量之後,在整個程式執行期間它們的值都不能再發生變化了。多個常...

Go語言之Go語言網路程式設計

go語言的 net 包中有乙個 tcpconn 型別,可以用來建立 tcp 客戶端和 tcp 伺服器端間的通訊通道,tcpconn 型別裡有兩個主要的函式 func c tcpconn write b byte n int,err os.error func c tcpconn read b byt...

Go語言之Go 語言迴圈語句

go 語言提供了以下幾種型別迴圈處理語句 迴圈型別 描述for 迴圈 重複執行語句塊 迴圈巢狀 在 for 迴圈中巢狀乙個或多個 for 迴圈 迴圈控制語句可以控制迴圈體內語句的執行過程。go 語言支援以下幾種迴圈控制語句 控制語句 描述break 語句 經常用於中斷當前 for 迴圈或跳出 swi...