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

淺談Golang內(nèi)存逃逸

 更新時(shí)間:2022年08月08日 10:51:40   作者:南一道街丶  
本文主要介紹了Golang內(nèi)存逃逸,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

1.什么是內(nèi)存逃逸

在一段程序中,每一個(gè)函數(shù)都會(huì)有自己的內(nèi)存區(qū)域分配自己的局部變量,返回值,這些內(nèi)存會(huì)由編譯器在棧中進(jìn)行分配,每一個(gè)函數(shù)會(huì)分配一個(gè)棧幀,在函數(shù)運(yùn)行結(jié)束后銷毀,但是有些變量我們想在函數(shù)運(yùn)行結(jié)束后仍然使用,就需要把這個(gè)變量分配在堆上,這種從“棧”上逃逸到“堆”上的現(xiàn)象叫做內(nèi)存逃逸

2.什么是逃逸分析

雖然Go語(yǔ)言引入的Gc,GC機(jī)制會(huì)對(duì)堆上的對(duì)象進(jìn)行管理,當(dāng)某個(gè)對(duì)象不可達(dá)(沒(méi)有其他對(duì)象引用他),他將會(huì)被回收。雖然GC可以降低工作人員負(fù)擔(dān),但是GC也會(huì)給程序帶來(lái)性能損耗,當(dāng)堆內(nèi)存上有大量的堆內(nèi)存對(duì)象,就會(huì)給GC很大的壓力,雖然Go語(yǔ)言使用的是標(biāo)記清除算法,并且在此基礎(chǔ)上使用了三色標(biāo)記法和寫屏障技術(shù),但是我們?cè)诙焉戏峙浯罅績(jī)?nèi)存,仍然會(huì)對(duì)GC造成很大壓力,Go引入了逃逸分析,就是想減少堆內(nèi)存的分配,可以在棧分配的內(nèi)存盡量分配在棧上

3.小結(jié)

逃逸分析就是在程序編譯階段根據(jù)代碼中的數(shù)據(jù)流,對(duì)代碼中哪些變量需要在棧上分配,哪些需要在對(duì)象分配的靜態(tài)分析方法,堆和棧相比,堆適合分配不可預(yù)知大小的內(nèi)存,但是付出代價(jià)是分配速度慢,容易產(chǎn)生碎片,棧分配十分快,棧分配只需要兩個(gè)指令“Push”和"Release"分配和釋放,而且堆分配需要先找一塊適合大小的內(nèi)存塊分配,需要垃圾回收釋放,所以逃逸分析可以更好的做內(nèi)存分配

Go語(yǔ)言的逃逸分析

src/cmd/compile/internal/gc/escape.go

  • pointers to stack objects cannot be stored in the heap: 指向棧對(duì)象的指針不能存儲(chǔ)在堆中
  • pointers to a stack object cannot outlive that object:指向棧對(duì)象的指針不能超過(guò)該對(duì)象的存活期,指針不能在棧對(duì)象銷毀之后依然存活(例子:聲明的函數(shù)返回并銷毀了對(duì)象的棧幀,或者它在循環(huán)迭代中被重復(fù)用于邏輯上不同的變量)

既然逃逸分析是在編譯階段進(jìn)行的,那我們就可以通過(guò)go build -gcflga '-m -m l'查看逃逸分析結(jié)果

4.逃逸分析案例

1.函數(shù)返回局部指針變量

func Add(x,y int) *int {
 res := 0
 res = x + y
 return &res
}
func main()  {
 Add(1,2)
}

.\pointer.go:4:2: res escapes to heap:
.\pointer.go:4:2:   flow: ~r2 = &res:
.\pointer.go:4:2:     from &res (address-of) at .\pointer.go:6:9
.\pointer.go:4:2:     from return &res (return) at .\pointer.go:6:2
.\pointer.go:4:2: moved to heap: res

函數(shù)返回局部變量是一個(gè)指針變量,函數(shù)Add執(zhí)行結(jié)束,對(duì)應(yīng)棧幀就會(huì)銷毀,但是引用返回到函數(shù)外部,如果我們外部解析地址,就會(huì)導(dǎo)致程序訪問(wèn)非法內(nèi)存,所以經(jīng)過(guò)編輯器分析過(guò)后將其在堆上分配

2.interface類型逃逸

1.interface產(chǎn)生逃逸

func main()  {
   str := "荔枝"
   fmt.Println(str)
}

E:\GoStudy\src\HighBase\Escape>go build -gcflags="-m -m -l" ./pointer.go
# command-line-arguments
.\pointer.go:20:13: str escapes to heap:
.\pointer.go:20:13:   flow: {storage for ... argument} = &{storage for str}:
.\pointer.go:20:13:     from str (spill) at .\pointer.go:20:13
.\pointer.go:20:13:     from ... argument (slice-literal-element) at .\pointer.go:20:13
.\pointer.go:20:13:   flow: {heap} = {storage for ... argument}:
.\pointer.go:20:13:     from ... argument (spill) at .\pointer.go:20:13
.\pointer.go:20:13:     from fmt.Println(... argument...) (call parameter) at .\pointer.go:20:13
.\pointer.go:20:13: ... argument does not escape
.\pointer.go:20:13: str escapes to heap

str是main的一個(gè)局部變量,傳給 fmt.Printl()之后逃逸,因?yàn)閒mt.Println()的入?yún)⑹莍nterface{}類型,如果參數(shù)為interface{},那么編譯期間就很難確定參數(shù)類型

2.指向棧對(duì)象的指針不能在堆中

我們把代碼改成這樣

func main()  {
   str := "蘇珊"
   fmt.Println(&str)
}

# command-line-arguments
.\pointer.go:19:2: str escapes to heap:
.\pointer.go:19:2:   flow: {storage for ... argument} = &str:
.\pointer.go:19:2:     from &str (address-of) at .\pointer.go:20:14
.\pointer.go:19:2:     from &str (interface-converted) at .\pointer.go:20:14
.\pointer.go:19:2:     from ... argument (slice-literal-element) at .\pointer.go:20:13
.\pointer.go:19:2:   flow: {heap} = {storage for ... argument}:
.\pointer.go:19:2:     from ... argument (spill) at .\pointer.go:20:13
.\pointer.go:19:2:     from fmt.Println(... argument...) (call parameter) at .\pointer.go:20:13
.\pointer.go:19:2: moved to heap: str
.\pointer.go:20:13: ... argument does not escape

這次str也逃逸到堆上面了,在堆上面進(jìn)行分配,因?yàn)槿雲(yún)⑹莍nterface,變量str的地址被以實(shí)參的方式傳入fmt.Println被裝箱到一個(gè)interface{}

裝箱的形參變量要在堆上分配,但是還需要存儲(chǔ)一個(gè)棧上的地址,這和之前說(shuō)的第一條不符,所以str也會(huì)分配到堆上

3.閉包產(chǎn)生逃逸

func Increase() func() int {
?n := 0
?return func() int {
? n++
? return n
?}
}

func main() {
?in := Increase()
?fmt.Println(in()) // 1
}

E:\GoStudy\src\HighBase\Escape>go build -gcflags "-m -m -l" ./pointer.go
# command-line-arguments
.\pointer.go:27:2: Increase capturing by ref: n (addr=false assign=true width=8)
.\pointer.go:28:9: func literal escapes to heap:
.\pointer.go:28:9:   flow: ~r0 = &{storage for func literal}:
.\pointer.go:28:9:     from func literal (spill) at .\pointer.go:28:9
.\pointer.go:28:9:     from return func literal (return) at .\pointer.go:28:2
.\pointer.go:27:2: n escapes to heap:
.\pointer.go:27:2:   flow: {storage for func literal} = &n:
.\pointer.go:27:2:     from n (captured by a closure) at .\pointer.go:29:3
.\pointer.go:27:2:     from n (reference) at .\pointer.go:29:3
.\pointer.go:27:2: moved to heap: n
.\pointer.go:28:9: func literal escapes to heap
.\pointer.go:36:16: in() escapes to heap:
.\pointer.go:36:16:   flow: {storage for ... argument} = &{storage for in()}:
.\pointer.go:36:16:     from in() (spill) at .\pointer.go:36:16
.\pointer.go:36:16:     from ... argument (slice-literal-element) at .\pointer.go:36:13
.\pointer.go:36:16:   flow: {heap} = {storage for ... argument}:
.\pointer.go:36:16:     from ... argument (spill) at .\pointer.go:36:13
.\pointer.go:36:16:     from fmt.Println(... argument...) (call parameter) at .\pointer.go:36:13
.\pointer.go:36:13: ... argument does not escape
.\pointer.go:36:16: in() escapes to heap

因?yàn)楹瘮?shù)是指針類型,所以匿名函數(shù)當(dāng)做返回值產(chǎn)生逃逸,匿名函數(shù)使用外部變量n,這個(gè)n會(huì)一直存在知道in被銷毀

4. 變量大小不確定及??臻g不足引發(fā)逃逸

import (
?? ?"math/rand"
)

func LessThan8192() ?{
?? ?nums := make([]int, 100) // = 64KB
?? ?for i := 0; i < len(nums); i++ {
?? ??? ?nums[i] = rand.Int()
?? ?}
}


func MoreThan8192(){
?? ?nums := make([]int, 1000000) // = 64KB
?? ?for i := 0; i < len(nums); i++ {
?? ??? ?nums[i] = rand.Int()
?? ?}
}


func NonConstant() {
?? ?number := 10
?? ?s := make([]int, number)
?? ?for i := 0; i < len(s); i++ {
?? ??? ?s[i] = i
?? ?}
}

func main() {
?? ?NonConstant()
?? ?MoreThan8192()
?? ?LessThan8192()
}

# command-line-arguments
.\pointer.go:43:14: make([]int, 100) does not escape
.\pointer.go:51:14: make([]int, 1000000) escapes to heap:
.\pointer.go:51:14:   flow: {heap} = &{storage for make([]int, 1000000)}:
.\pointer.go:51:14:     from make([]int, 1000000) (too large for stack) at .\pointer.go:51:14
.\pointer.go:51:14: make([]int, 1000000) escapes to heap
.\pointer.go:60:11: make([]int, number) escapes to heap:
.\pointer.go:60:11:   flow: {heap} = &{storage for make([]int, number)}:
.\pointer.go:60:11:     from make([]int, number) (non-constant size) at .\pointer.go:60:11
.\pointer.go:60:11: make([]int, number) escapes to heap

??臻g足夠不會(huì)發(fā)生逃逸,但是變量過(guò)大,已經(jīng)超過(guò)??臻g,會(huì)逃逸到堆上

5.總結(jié)

  • 逃逸分析在編譯階段確定哪些變量可以分配在棧中,哪些變量分配在堆上
  • 逃逸分析減輕了GC壓力,提高程序的運(yùn)行速度
  • 棧上內(nèi)存使用完畢不需要GC處理,堆上內(nèi)存使用完畢會(huì)交給GC處理
  • 函數(shù)傳參時(shí)對(duì)于需要修改原對(duì)象值,或占用內(nèi)存比較大的結(jié)構(gòu)體,選擇傳指針。對(duì)于只讀的占用內(nèi)存較小的結(jié)構(gòu)體,直接傳值能夠獲得更好的性能
  • 根據(jù)代碼具體分析,盡量減少逃逸代碼,減輕GC壓力,提高性能

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

相關(guān)文章

  • GOLANG版的冒泡排序和快速排序分享

    GOLANG版的冒泡排序和快速排序分享

    這篇文章主要介紹了GOLANG版的冒泡排序和快速排序分享,需要的朋友可以參考下
    2015-03-03
  • Golang中的time.Duration類型用法說(shuō)明

    Golang中的time.Duration類型用法說(shuō)明

    這篇文章主要介紹了Golang中的time.Duration類型用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • Go?for-range?的?value值地址每次都一樣的原因解析

    Go?for-range?的?value值地址每次都一樣的原因解析

    循環(huán)語(yǔ)句是一種常用的控制結(jié)構(gòu),在?Go?語(yǔ)言中,除了?for?關(guān)鍵字以外,還有一個(gè)?range?關(guān)鍵字,可以使用?for-range?循環(huán)迭代數(shù)組、切片、字符串、map?和?channel?這些數(shù)據(jù)類型,這篇文章主要介紹了Go?for-range?的?value值地址每次都一樣的原因解析,需要的朋友可以參考下
    2023-05-05
  • go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie

    go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie

    這篇文章主要介紹了go語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之前綴樹(shù)Trie,文章圍繞主題展開(kāi)詳細(xì)內(nèi)容介紹,具有一定得參考價(jià)值,需要的小伙伴可以參考一下
    2022-05-05
  • 詳解Golang如何實(shí)現(xiàn)節(jié)假日不打擾用戶

    詳解Golang如何實(shí)現(xiàn)節(jié)假日不打擾用戶

    這篇文章主要為大家介紹了Golang如何實(shí)現(xiàn)節(jié)假日不打擾用戶過(guò)程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • 一文詳解Golang中的匿名變量

    一文詳解Golang中的匿名變量

    匿名變量是一種特殊類型的變量,可以簡(jiǎn)化代碼并提高可讀性,本文將為大家詳細(xì)介紹一下golang中匿名變量的定義、特性和使用方法,需要的可以參考下
    2023-09-09
  • Go 加密解密算法小結(jié)

    Go 加密解密算法小結(jié)

    加密解密在實(shí)際開(kāi)發(fā)中應(yīng)用比較廣泛,常見(jiàn)的加解密分為三種,本文就詳細(xì)的介紹一下Go 加密解密算法,具有一定的參考價(jià)值,感興趣的可以了解一下
    2022-01-01
  • 詳解Golang?ProtoBuf的基本語(yǔ)法總結(jié)

    詳解Golang?ProtoBuf的基本語(yǔ)法總結(jié)

    最近項(xiàng)目是采用微服務(wù)架構(gòu)開(kāi)發(fā)的,各服務(wù)之間通過(guò)gPRC調(diào)用,基于ProtoBuf序列化協(xié)議進(jìn)行數(shù)據(jù)通信,因此接觸學(xué)習(xí)了Protobuf,本文會(huì)對(duì)Protobuf的語(yǔ)法做下總結(jié),感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助
    2022-10-10
  • Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法

    Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法

    這篇文章主要介紹了Go語(yǔ)言導(dǎo)出內(nèi)容到Excel的方法,涉及Go語(yǔ)言操作excel的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • golang 格式化輸入輸出操作

    golang 格式化輸入輸出操作

    這篇文章主要介紹了golang 格式化輸入輸出操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12

最新評(píng)論

望谟县| 清原| 清流县| 高州市| 广昌县| 桐乡市| 阿克苏市| 新河县| 崇阳县| 虹口区| 灵山县| 正定县| 永春县| 武冈市| 隆尧县| 乳山市| 周口市| 米易县| 江达县| 商都县| 泗洪县| 曲阜市| 吴川市| 东乌珠穆沁旗| 蓬安县| 萨迦县| 丰顺县| 蕉岭县| 平泉县| 孙吴县| 都兰县| 保康县| 大洼县| 类乌齐县| 大新县| 富顺县| 开原市| 兴安县| 木兰县| 四川省| 藁城市|