最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang內(nèi)存逃逸分析

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

一、編譯器的逃逸分析

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

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

我們看如下代碼:

package main

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

//go:noinline    內(nèi)置的編譯指令,可以強(qiáng)制讓 Go 編譯器不對指定的函數(shù)進(jìn)行內(nèi)聯(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 放在堆中開辟

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

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

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

二、new的變量內(nèi)存分配在棧還是堆上?

new 出來的變量,內(nèi)存一定是分配在堆上嗎?

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

package main

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

//go:noinline    內(nèi)置的編譯指令,可以強(qiáng)制讓 Go 編譯器不對指定的函數(shù)進(jìn)行內(nèi)聯(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ù)的內(nèi)存空間,依然具備逃逸行為。所以這里不是分配在堆上的。

結(jié)論:

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

三、逃逸規(guī)則

一般我們給一個引用類對象中的引用類成員進(jìn)行賦值,就可能會出現(xiàn)逃逸現(xiàn)象??梢岳斫鉃樵L問一個引用對象實(shí)際上底層就是通過一個指針來間接的訪問了,但是如果再訪問里面的引用成員就會有第二次間接訪問,這樣操作這部分對象的話,就有可能會出現(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{} 類型嘗試進(jìn)行賦值,必定出現(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{} 類型嘗試通過賦值,會導(dǎo)致key 和 value 的賦值出現(xiàn)逃逸

package main

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

看看編譯結(jié)果:

 ~/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ù)類型,賦值的右側(cè)會發(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ā)生了逃逸

四、結(jié)論

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

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

相關(guān)文章

  • Go語言結(jié)合GORM實(shí)現(xiàn)數(shù)據(jù)庫事務(wù)處理的示例代碼

    Go語言結(jié)合GORM實(shí)現(xiàn)數(shù)據(jù)庫事務(wù)處理的示例代碼

    這篇文章主要為大家詳細(xì)介紹了Go語言結(jié)合GORM實(shí)現(xiàn)數(shù)據(jù)庫事務(wù)處理的相關(guān)知識,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-08-08
  • 在 Golang 中實(shí)現(xiàn)一個簡單的Http中間件過程詳解

    在 Golang 中實(shí)現(xiàn)一個簡單的Http中間件過程詳解

    本文在go web中簡單的實(shí)現(xiàn)了中間件的機(jī)制,這樣帶來的好處也是顯而易見的,當(dāng)然社區(qū)也有一些成熟的 middleware 組件,包括 Gin 一些Web框架中也包含了 middleware 相關(guān)的功能,具體內(nèi)容詳情跟隨小編一起看看吧
    2021-07-07
  • Golang的關(guān)鍵字defer的使用方法

    Golang的關(guān)鍵字defer的使用方法

    這篇文章主要介紹了Golang的關(guān)鍵字defer的使用方法,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-06-06
  • golang接口IP限流,IP黑名單,IP白名單的實(shí)例

    golang接口IP限流,IP黑名單,IP白名單的實(shí)例

    這篇文章主要介紹了golang接口IP限流,IP黑名單,IP白名單的實(shí)例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go語言中JSON文件的讀寫操作

    Go語言中JSON文件的讀寫操作

    本文主要介紹了Go語言JSON文件的讀寫操作,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • go語言中的Carbon庫時間處理技巧

    go語言中的Carbon庫時間處理技巧

    這篇文章主要介紹了go語言中的Carbon庫時間處理,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • 手把手帶你走進(jìn)Go語言之類型轉(zhuǎn)換

    手把手帶你走進(jìn)Go語言之類型轉(zhuǎn)換

    每個函數(shù)都可以強(qiáng)制將一個表達(dá)式轉(zhuǎn)換成某種特定數(shù)據(jù)類型,本文給大家介紹了在Go語言中類型轉(zhuǎn)換的具體用法,講述的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值
    2021-09-09
  • Go語言變量與基礎(chǔ)數(shù)據(jù)類型詳情

    Go語言變量與基礎(chǔ)數(shù)據(jù)類型詳情

    Go 是靜態(tài)(編譯型)語言,是區(qū)別于解釋型語言的弱類型語言(靜態(tài):類型固定,強(qiáng)類型:不同類型不允許直接運(yùn)算),下面文章將對其進(jìn)行詳細(xì)介紹,需要的朋友可以參考一下
    2021-09-09
  • Go語言七篇入門教程二程序結(jié)構(gòu)與數(shù)據(jù)類型

    Go語言七篇入門教程二程序結(jié)構(gòu)與數(shù)據(jù)類型

    這篇文章主要為大家介紹了Go語言的程序結(jié)構(gòu)與數(shù)據(jù)類型,本篇文章是Go語言七篇入門系列文,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2021-11-11
  • 淺析在Go語言中如何實(shí)現(xiàn)協(xié)程池

    淺析在Go語言中如何實(shí)現(xiàn)協(xié)程池

    gammazero/workerpool?就是用來實(shí)現(xiàn)協(xié)程池的?Go?包,本文我們將一起來學(xué)習(xí)一下其使用方法,并深入其源碼來探究下如何實(shí)現(xiàn)一個?Go?協(xié)程池,需要的可以了解下
    2025-06-06

最新評論

延边| 阜城县| 永和县| 垣曲县| 兴化市| 高密市| 合山市| 抚顺县| 禄劝| 南和县| 海安县| 新干县| 英山县| 松江区| 江都市| 淮安市| 小金县| 胶南市| 大港区| 山东省| 营山县| 本溪市| 丽水市| 凤庆县| 盐山县| 长治市| 双城市| 正定县| 辉南县| 上犹县| 盐源县| 肇东市| 本溪市| 济南市| 额敏县| 通州区| 南和县| 桂林市| 田林县| 绥棱县| 寻甸|