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

Go語(yǔ)言中內(nèi)存管理逃逸分析詳解

 更新時(shí)間:2023年03月15日 09:29:06   作者:failymao  
所謂的逃逸分析(Escape?analysis)是指由編譯器決定內(nèi)存分配的位置嗎不需要程序員指定。本文就來(lái)和大家簡(jiǎn)單分析一下Go語(yǔ)言中內(nèi)存管理逃逸吧

1. 前言

所謂的逃逸分析(Escape analysis)是指由編譯器決定內(nèi)存分配的位置嗎不需要程序員指定。

函數(shù)中申請(qǐng)一個(gè)新的對(duì)象

  • 如果分配在棧中, 則函數(shù)執(zhí)行結(jié)束后可自動(dòng)將內(nèi)存回收
  • 如果分配在堆中, 則函數(shù)執(zhí)行借宿可交給GC(垃圾回收)處理

有了逃逸分析,返回函數(shù)局部變量將變得可能,除此之外,逃逸分析還跟閉包息息相關(guān),了解哪些場(chǎng)景下對(duì)象會(huì)逃逸至關(guān)重要。

2. 逃逸策略

每當(dāng)函數(shù)中申請(qǐng)新的對(duì)象,編譯器會(huì)根據(jù)該對(duì)象是否被函數(shù)外部引用來(lái)決定是否逃逸:

  • 如果函數(shù)外部沒(méi)有引用,則優(yōu)先放到棧中;
  • 如果函數(shù)外部存在引用,則必定放到堆中;

注意,對(duì)于函數(shù)外部沒(méi)有引用的對(duì)象,也有可能放到堆中,比如內(nèi)存過(guò)大超過(guò)棧的存儲(chǔ)能力。

3. 逃逸場(chǎng)景

3.1 指針逃逸

我們知道Go可以返回局部變量指針,這其實(shí)是一個(gè)典型的變量逃逸案例,示例代碼如下:

package main
 
type Student struct {
    Name string
    Age  int
}
 
func StudentRegister(name string, age int) *Student {
    s := new(Student) //局部變量s逃逸到堆
 
    s.Name = name
    s.Age = age
 
    return s
}
 
func main() {
    StudentRegister("Jim", 18)
}

函數(shù)StudentRegister()內(nèi)部s為局部變量,其值通過(guò)函數(shù)返回值返回,s本身為一指針,其指向的內(nèi)存地址不會(huì)是棧而是堆,這就是典型的逃逸案例。

通過(guò)編譯參數(shù)-gcflag=-m可以查看編譯過(guò)程中的逃逸分析:

D:\SourceCode\GoExpert\src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/src
.\main.go:8: can inline StudentRegister
.\main.go:17: can inline main
.\main.go:18: inlining call to StudentRegister
.\main.go:8: leaking param: name
.\main.go:9: new(Student) escapes to heap
.\main.go:18: main new(Student) does not escape

可見(jiàn)在StudentRegister()函數(shù)中,也即代碼第9行顯示”escapes to heap”,代表該行內(nèi)存分配發(fā)生了逃逸現(xiàn)象。

3.2 ??臻g不足逃逸

看下面的代碼,是否會(huì)產(chǎn)生逃逸呢?

package main
 
func Slice() {
    s := make([]int, 1000, 1000)
 
    for index, _ := range s {
        s[index] = index
    }
}
 
func main() {
    Slice()
}

上面代碼Slice()函數(shù)中分配了一個(gè)1000個(gè)長(zhǎng)度的切片,是否逃逸取決于??臻g是否足夠大。

直接查看編譯提示,如下:

D:\SourceCode\GoExpert\src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/src
.\main.go:4: Slice make([]int, 1000, 1000) does not escape

我們發(fā)現(xiàn)此處并沒(méi)有發(fā)生逃逸。那么把切片長(zhǎng)度擴(kuò)大10倍即10000會(huì)如何呢?

D:\SourceCode\GoExpert\src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/src
.\main.go:4: make([]int, 10000, 10000) escapes to heap

我們發(fā)現(xiàn)當(dāng)切片長(zhǎng)度擴(kuò)大到10000時(shí)就會(huì)逃逸。

實(shí)際上當(dāng)??臻g不足以存放當(dāng)前對(duì)象時(shí)或無(wú)法判斷當(dāng)前切片長(zhǎng)度時(shí)會(huì)將對(duì)象分配到堆中。

3.3 動(dòng)態(tài)類型逃逸

很多函數(shù)參數(shù)為interface類型,比如fmt.Println(a …interface{}),編譯期間很難確定其參數(shù)的具體類型,也會(huì)產(chǎn)生逃逸。

如下代碼所示:

package main
 
import "fmt"
 
func main() {
    s := "Escape"
    fmt.Println(s)
}

上述代碼s變量只是一個(gè)string類型變量,調(diào)用fmt.Println()時(shí)會(huì)產(chǎn)生逃逸:

D:\SourceCode\GoExpert\src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/src
.\main.go:7: s escapes to heap
.\main.go:7: main ... argument does not escape

3.4 閉包引用對(duì)象逃逸

某著名的開(kāi)源框架實(shí)現(xiàn)了某個(gè)返回Fibonacci數(shù)列的函數(shù):

func Fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}

該函數(shù)返回一個(gè)閉包,閉包引用了函數(shù)的局部變量a和b,使用時(shí)通過(guò)該函數(shù)獲取該閉包,然后每次執(zhí)行閉包都會(huì)依次輸出Fibonacci數(shù)列。
完整的示例程序如下所示:

package main
 
import "fmt"
 
func Fibonacci() func() int {
    a, b := 0, 1
    return func() int {
        a, b = b, a+b
        return a
    }
}
 
func main() {
    f := Fibonacci()
 
    for i := 0; i < 10; i++ {
        fmt.Printf("Fibonacci: %d\n", f())
    }
}

上述代碼通過(guò)Fibonacci()獲取一個(gè)閉包,每次執(zhí)行閉包就會(huì)打印一個(gè)Fibonacci數(shù)值。輸出如下所示:

D:\SourceCode\GoExpert\src>src.exe
Fibonacci: 1
Fibonacci: 1
Fibonacci: 2
Fibonacci: 3
Fibonacci: 5
Fibonacci: 8
Fibonacci: 13
Fibonacci: 21
Fibonacci: 34
Fibonacci: 55

Fibonacci()函數(shù)中原本屬于局部變量的a和b由于閉包的引用,不得不將二者放到堆上,以致產(chǎn)生逃逸:

D:\SourceCode\GoExpert\src>go build -gcflags=-m
# _/D_/SourceCode/GoExpert/src
.\main.go:7: can inline Fibonacci.func1
.\main.go:7: func literal escapes to heap
.\main.go:7: func literal escapes to heap
.\main.go:8: &a escapes to heap
.\main.go:6: moved to heap: a
.\main.go:8: &b escapes to heap
.\main.go:6: moved to heap: b
.\main.go:17: f() escapes to heap
.\main.go:17: main ... argument does not escape

4.逃逸總結(jié)

棧上分配內(nèi)存比在堆中分配內(nèi)存有更高的效率

棧上分配的內(nèi)存不需要GC處理

堆上分配的內(nèi)存使用完畢會(huì)交給GC處理

逃逸分析目的是決定內(nèi)分配地址是棧還是堆

逃逸分析在編譯階段完成

5. 注意事項(xiàng)

思考一下這個(gè)問(wèn)題:函數(shù)傳遞指針真的比傳值效率高嗎?

我們知道傳遞指針可以減少底層值的拷貝,可以提高效率,但是如果拷貝的數(shù)據(jù)量小,由于指針傳遞會(huì)產(chǎn)生逃逸,可能會(huì)使用堆,也可能會(huì)增加GC的負(fù)擔(dān),所以傳遞指針不一定是高效的。

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

相關(guān)文章

  • golang?gorm的Callbacks事務(wù)回滾對(duì)象操作示例

    golang?gorm的Callbacks事務(wù)回滾對(duì)象操作示例

    這篇文章主要為大家介紹了golang?gorm的Callbacks事務(wù)回滾對(duì)象操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • golang中的三個(gè)點(diǎn) ''...''的用法示例詳解

    golang中的三個(gè)點(diǎn) ''...''的用法示例詳解

    這篇文章主要介紹了golang中的三個(gè)點(diǎn) '...' 的用法示例詳解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Go語(yǔ)言如何實(shí)現(xiàn)TCP通信詳解

    Go語(yǔ)言如何實(shí)現(xiàn)TCP通信詳解

    go里面實(shí)現(xiàn)tcp沒(méi)有像之前寫(xiě)的C++那些那么麻煩,在C++里面要先創(chuàng)建套接字,然后綁定ip地址,go里面直接就一個(gè)函數(shù)建立套接字,然后在進(jìn)行通信就可以了,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言如何實(shí)現(xiàn)TCP通信的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • Go語(yǔ)言實(shí)現(xiàn)廣播式并發(fā)聊天服務(wù)器

    Go語(yǔ)言實(shí)現(xiàn)廣播式并發(fā)聊天服務(wù)器

    本文主要介紹了Go語(yǔ)言實(shí)現(xiàn)廣播式并發(fā)聊天服務(wù)器,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • Golang中的關(guān)鍵字(defer、:=、go?func())詳細(xì)解讀

    Golang中的關(guān)鍵字(defer、:=、go?func())詳細(xì)解讀

    這篇文章主要介紹了Golang中的關(guān)鍵字(defer、:=、go?func())詳細(xì)解讀,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-04-04
  • 關(guān)于Golang中for-loop與goroutine的問(wèn)題詳解

    關(guān)于Golang中for-loop與goroutine的問(wèn)題詳解

    這篇文章主要給大家介紹了關(guān)于Golang中for-loop與goroutine問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用golang具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-09-09
  • Golang中禁止拷貝的實(shí)現(xiàn)代碼

    Golang中禁止拷貝的實(shí)現(xiàn)代碼

    這篇文章主要給大家介紹了關(guān)于Golang中實(shí)現(xiàn)禁止拷貝的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • Go 1.23中Timer無(wú)buffer的實(shí)現(xiàn)方式詳解

    Go 1.23中Timer無(wú)buffer的實(shí)現(xiàn)方式詳解

    在 Go 1.23 中,Timer 的實(shí)現(xiàn)通常是通過(guò) time 包提供的 time.Timer 類型來(lái)實(shí)現(xiàn)的,本文主要介紹了Go 1.23中Timer無(wú)buffer的實(shí)現(xiàn)方式,需要的可以了解下
    2025-03-03
  • 一文搞懂Golang 時(shí)間和日期相關(guān)函數(shù)

    一文搞懂Golang 時(shí)間和日期相關(guān)函數(shù)

    這篇文章主要介紹了Golang 時(shí)間和日期相關(guān)函數(shù),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-12-12
  • Go語(yǔ)言中io包核心接口示例詳解

    Go語(yǔ)言中io包核心接口示例詳解

    Go的io包提供了io.Reader和io.Writer接口,分別用于數(shù)據(jù)的輸入和輸出,下面這篇文章主要給大家介紹了關(guān)于Go語(yǔ)言中io包核心接口的相關(guān)資料,需要的朋友可以參考下
    2021-12-12

最新評(píng)論

江华| 榆林市| 健康| 南木林县| 呼和浩特市| 武山县| 五常市| 香港 | 富川| 山东| 广德县| 锡林郭勒盟| 贺兰县| 新竹市| 五寨县| 大理市| 山阳县| 弋阳县| 星子县| 五河县| 义马市| 宕昌县| 金平| 卢龙县| 阳城县| 乌拉特中旗| 上蔡县| 禄丰县| 寿阳县| 东海县| 宝丰县| 清流县| 青铜峡市| 安溪县| 会东县| 岳西县| 东平县| 且末县| 公主岭市| 唐山市| 集贤县|