欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

golang內存逃逸分析

 更新時間:2025年06月09日 10:10:21   作者:瘋狂的程需猿  
本文主要介紹了golang內存逃逸分析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

一、編譯器的逃逸分析

go語言編譯器會自動決定把一個變量放在堆上還是放在棧上,編譯器會做逃逸分析,當發(fā)現(xiàn)變量的作用域沒有跑出函數(shù)范圍(懸空指針),就可以在棧上,否則則必須分配在堆上。

這樣可以釋放程序員關于內存的使用限制,更多的讓程序員關注于程序功能邏輯本身。

我們看如下代碼:

package main

func main() {
	// 打印返回的指針地址
	println(fool())
	// 0x1400008e000
}

//go:noinline    內置的編譯指令,可以強制讓 Go 編譯器不對指定的函數(shù)進行內聯(lián)優(yōu)化
func fool() *int {
	var (
		a = 1
		b = 2
		c = 3
		d = 4
		e = 5
	)
	println(&a, &b, &c, &d, &e)
	// 0x14000066f38 0x14000066f30 0x1400008e000 0x14000066f28 0x14000066f20
	return &c
}

我們能看到**c**是返回給main 的局部變量,其中它的地址值是 0x1400008e000 很明顯與其他的 a b d e 不是連續(xù)的。

我們用go tool compile測試一下

 ~/workspace/test  go tool compile -m main.go
main.go:3:6: can inline main
main.go:14:3: moved to heap: c

果然,在編譯的時候,c 被編譯器判定為逃逸變量,將c 放在堆中開辟

內聯(lián): go編譯器會對一些小函數(shù)進行內聯(lián)優(yōu)化,以提升性能。內聯(lián)優(yōu)化意味著函數(shù)的代碼會在調用處直接展開,而不是常規(guī)的函數(shù)調用。這就導致一些逃逸分析的行為發(fā)生變化,類似上面那個代碼的內存地址就會是連續(xù)的。

什么時候編譯器會進行內聯(lián)優(yōu)化?

  • 函數(shù)體較?。篏o編譯器更容易將體積較小的函數(shù)進行內聯(lián)
  • 無復雜控制結構:如果函數(shù)內沒有復雜的循環(huán),條件分支等……內聯(lián)的可能性更高
  • 函數(shù)參數(shù)和返回值簡單:函數(shù)參數(shù)和返回值不過于復雜也有助于函數(shù)的內聯(lián)

二、new的變量內存分配在棧還是堆上?

new 出來的變量,內存一定是分配在堆上嗎?

還是原來的代碼,我們通過new 分開來看看:

package main

func main() {
	// 打印返回的指針地址
	println(fool())
	// 0x1400001a0a0
}

//go:noinline    內置的編譯指令,可以強制讓 Go 編譯器不對指定的函數(shù)進行內聯(lián)優(yōu)化
func fool() *int {
	var (
		a = new(int)
		b = new(int)
		c = new(int)
		d = new(int)
		e = new(int)
	)
	println(a, b, c, d, e)
	// 0x14000098f38 0x14000098f30 0x1400001a0a0 0x14000098f28 0x14000098f20
	return c
}

很明顯,c 的地址 0x1400001a0a0 依然和其他的不是連續(xù)的內存空間,依然具備逃逸行為。所以這里不是分配在堆上的。

結論:

  • new 并不強制堆分配: 使用 new (T)分配的變量不一定分配在堆上,依然依賴于 Go 編譯器的逃逸分析結果。
  • 是否逃逸決定了內存分配的位置:如果變量需要在函數(shù)作用域外使用(逃逸),則分配在堆上;如果可以在局部棧中管理,則分配在棧上。

三、逃逸規(guī)則

一般我們給一個引用類對象中的引用類成員進行賦值,就可能會出現(xiàn)逃逸現(xiàn)象??梢岳斫鉃樵L問一個引用對象實際上底層就是通過一個指針來間接的訪問了,但是如果再訪問里面的引用成員就會有第二次間接訪問,這樣操作這部分對象的話,就有可能會出現(xiàn)逃逸現(xiàn)象了。

Go 語言的引用類型有:func(函數(shù)類型)、 interface(接口類型)、slice(切片類型)、 map(字典類型)、 channel(管道類型)、 *(指針類型) 等.

案例1

如果一個函數(shù)作為值傳遞給另一個函數(shù),或者被作為閉包使用,生命周期超出其原始作用域,則它會逃逸。

package main

func main() {
	foo()()
}

//go:noinline
func foo() func() {
	return func() {
		println("call")
	}
}

通過編譯看看逃逸分析:

~/workspace/test  go tool compile -m main.go
main.go:9:9: can inline foo.func1
main.go:9:9: func literal escapes to heap

能看到 發(fā)生了逃逸現(xiàn)象

案例2

對一個[]interface{} 類型嘗試進行賦值,必定出現(xiàn)逃逸

package main

//go:noinline
func main() {
	var a = []interface{}{"100", "1000"}
	a[0] = 10
}

逃逸分析:

 ~/workspace/test  go tool compile -m main.go
main.go:5:23: []interface {}{...} does not escape
main.go:5:24: "100" does not escape
main.go:5:31: "1000" does not escape
main.go:6:2: 10 escapes to heap

a[0]=10 發(fā)生了逃逸現(xiàn)象

案例3

map[string]interface{}類型嘗試通過賦值,必定出現(xiàn)逃逸

package main

//go:noinline
func main() {
	var a = make(map[string]interface{})
	a["hello"] = "world"
	a["1"] = "1"
}

逃逸分析:

 ~/workspace/test  go tool compile -m main.go
main.go:5:14: make(map[string]interface {}) does not escape
main.go:6:2: "world" escapes to heap
main.go:7:2: "1" escapes to heap

a["hello"] = "world" a["1"] = "1" 分別都發(fā)生了逃逸

案例4

map[interface{}]interface{} 類型嘗試通過賦值,會導致key 和 value 的賦值出現(xiàn)逃逸

package main

//go:noinline
func main() {
	var a = make(map[interface{}]interface{})
	a["hello"] = "world"
}

看看編譯結果:

 ~/workspace/test  go tool compile -m main.go
main.go:5:14: make(map[interface {}]interface {}) does not escape
main.go:6:2: "hello" escapes to heap
main.go:6:2: "world" escapes to heap

我們能看到,key 和 value 均發(fā)生了逃逸

案例5

map[string][]string數(shù)據(jù)類型,賦值 []string 會發(fā)生逃逸

package main

//go:noinline
func main() {
	var a = make(map[string][]string)
	a["hello"] = []string{"word1"}
}

通過逃逸分析發(fā)現(xiàn):

 ~/workspace/test  go tool compile -m main.go
main.go:5:14: make(map[string][]string) does not escape
main.go:6:23: []string{...} escapes to heap

[]string{…} 切片發(fā)生了逃逸

案例6

[]*int 數(shù)據(jù)類型,賦值的右側會發(fā)生逃逸

package main

//go:noinline
func main() {
	var a []*int
	var b = 3
	a = append(a, &b)
}

逃逸分析:

 ~/workspace/test  go tool compile -m main.go
main.go:6:6: moved to heap: b

其中 將 b 追加到 a 切片中, 最終 b 發(fā)生了逃逸

四、結論

golang 中的變量內存分配在堆上還是在棧上,是由編譯器做逃逸分析之后決定的。

到此這篇關于golang內存逃逸分析的文章就介紹到這了,更多相關golang 內存逃逸內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Golang 如何實現(xiàn)函數(shù)的任意類型傳參

    Golang 如何實現(xiàn)函數(shù)的任意類型傳參

    這篇文章主要介紹了Golang 實現(xiàn)函數(shù)的任意類型傳參操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go 1.22對net/http包的路由增強功能詳解

    Go 1.22對net/http包的路由增強功能詳解

    Go 1.22 版本對 net/http 包的路由功能進行了增強,引入了方法匹配(method matching)和通配符(wildcards)兩項新功能,本文將給大家詳細的介紹一下Go 1.22對net/http包的路由增強功能,需要的朋友可以參考下
    2024-02-02
  • Go實現(xiàn)圖片上添加水印的示例代碼

    Go實現(xiàn)圖片上添加水印的示例代碼

    本文主要介紹了Go實現(xiàn)圖片上添加水印的示例代碼,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-05-05
  • 詳解Go操作supervisor xml rpc接口及注意事項

    詳解Go操作supervisor xml rpc接口及注意事項

    這篇文章主要介紹了Go操作supervisor xml rpc接口及注意事項,管理web,在配置文件中配置相關信息,通過go-supervisor的處理庫進行操作,需要的朋友可以參考下
    2021-09-09
  • Go語言包管理工具dep的安裝與使用

    Go語言包管理工具dep的安裝與使用

    godep是解決包依賴的管理工具,下面這篇文章主要給大家介紹了關于Go語言包管理工具dep的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • Go 語言的指針的學習筆記

    Go 語言的指針的學習筆記

    這篇文章主要介紹了Go 語言的指針的學習筆記,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • Go語言Elasticsearch數(shù)據(jù)清理工具思路詳解

    Go語言Elasticsearch數(shù)據(jù)清理工具思路詳解

    這篇文章主要介紹了Go語言Elasticsearch數(shù)據(jù)清理工具思路詳解,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-10-10
  • 詳解Golang中NewTimer計時器的底層實現(xiàn)原理

    詳解Golang中NewTimer計時器的底層實現(xiàn)原理

    本文將主要介紹一下Go語言中的NewTimer,首先展示基于NewTimer創(chuàng)建的定時器來實現(xiàn)超時控制。接著通過一系列問題的跟進,展示了NewTimer的底層實現(xiàn)原理,需要的可以參考一下
    2023-05-05
  • 使用Go編譯為可執(zhí)行文件的方法實現(xiàn)

    使用Go編譯為可執(zhí)行文件的方法實現(xiàn)

    本文主要介紹了使用Go編譯為可執(zhí)行文件的方法實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2025-04-04
  • 深入刨析Golang-map底層原理

    深入刨析Golang-map底層原理

    這篇文章主要介紹了深入刨析Golang-map底層原理,Go 語言的 map 的使用非常簡易, 但其內部實現(xiàn)相對比較復雜,文中有相關的代碼示例,,需要的朋友可以參考下
    2023-05-05

最新評論