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

詳解Go語言中的逃逸分析

 更新時間:2023年09月15日 10:42:30   作者:similar  
逃逸分析是編譯器用于決定將變量分配到棧上還是堆上的一種行為,下面小編就來為大家詳細講講go語言中是如何進行逃逸分析的,需要的小伙伴可以參考下

什么是逃逸

一句話,逃逸分析是編譯器用于決定將變量分配到棧上還是堆上的一種行為。

眾所周知,函數(shù)的運行都在操作系統(tǒng)內(nèi)存空間中的棧空間內(nèi)。我們在棧上聲明臨時變量,分配內(nèi)存,函數(shù)運行完畢后,回收內(nèi)存。每個函數(shù)的??臻g都是獨立的,其他函數(shù)沒有權限訪問。但在某些情況下,我們需要在函數(shù)結束以后訪問棧上面的某些數(shù)據(jù),這就涉及到內(nèi)存逃逸了。

如果變量從棧上逃逸,那么他會逃到哪兒去呢?他會跑到堆上。由于棧上的變量是在函數(shù)結束的時候自動進行回收,回收代價比較??;而堆空間分配內(nèi)存,則首先需要找到一塊大小合適的內(nèi)存,之后通過GC回收才能釋放。對于這種情況,頻繁使用垃圾回收會占用比較大的開銷,所以要盡量分配內(nèi)存到棧上,減少GC的壓力。

逃逸分析基本過程

Go語言的逃逸分析最基本的原則:如果一個函數(shù)返回一個對變量的引用,那么他就會發(fā)生逃逸。

在任何情況下,如果一個值被分配到了??臻g以外的地方,那么它一定是被分配到了堆上。簡言之:編譯器會分析代碼的特征和生命周期,Go中的變量只有在編譯器可以證明在函數(shù)返回后不會再被引用的情況下,才會被分配到棧上,否則會被分配到堆上。

不同于C++中的new,Go語言中的new關鍵字不一定會將內(nèi)存分配到堆空間上,在Go語言中,沒有關鍵字或者函數(shù)可以直接將變量分配到堆上,而是通過編譯器來分析代碼決定將變量分配到何處。

一句話:

編譯器會根據(jù)變量是否被外部引用來決定是否逃逸。

如果函數(shù)外部沒有引用,則優(yōu)先放到棧中;

如果函數(shù)外部存在引用,則必定放到堆中;

常見逃逸情況

指針逃逸

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

比如:

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("similar", 18)
}

雖然函數(shù)StudentRegister內(nèi)部s為局部變量,但是由于返回了指針,其指向的內(nèi)存地址不會是棧而是堆,這是典型的逃逸案例。

使用命令 go build -gcflags '-m -l' main.go,得到:

# command-line-arguments
./escape.go:8:22: leaking param: name
./escape.go:9:10: new(Student) escapes to heap # 表示該行內(nèi)存發(fā)生了逃逸現(xiàn)象

??臻g不足

如果分配太大容量的slice在棧上,當棧空間不足存放當前對象或者無法判斷當前切片長度時就會將對象分配到堆中。

package main
func MakeSlice() {
	s := make([]int, 10000, 10000)
	for index := range(s){
		s[index] = index
	}
}
func main() {
	MakeSlice()
}

同樣使用命令go build -gcflags '-m -l' main.go:

# command-line-arguments
./escape_1.go:4:11: make([]int, 10000) escapes to heap

動態(tài)類型逃逸

很多函數(shù)的參數(shù)為interface類型,比如:

func Printf(format string, a ...interface{}) (n int, err error)
func Scanf(format string, a ...interface{}) (n int, err error)
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error)

在編譯時很難確定其參數(shù)的具體類型,也能產(chǎn)生逃逸。

變量大小不確定

在創(chuàng)建切片,初始化切片容量的時候,有時會傳入一個變量指定其大小,由于變量的值不能被編譯器確定,所以不能確定其占用空間大小,從而編譯器可能會直接將變量分配到堆上。

package main
func MakeSlice() {
	length := 1
	a := make([]int, length, length)
	for i := 0; i < length; i++ {
		a[i] = i
	}
}
func main() {
	MakeSlice()
}

編譯結果:

# command-line-arguments
./escape_1.go:5:11: make([]int, length, length) escapes to heap

常見的逃逸情況總結

指針逃逸:函數(shù)內(nèi)部返回一個局部變量指針

分配大對象:導致??臻g不足,不得不分配到堆上

調(diào)用接口類型的方法,接口類型的方法調(diào)用是動態(tài)調(diào)度 - 實際使用的具體實現(xiàn)只能在運行時確定。

盡管能夠符合分配到棧的場景,但是其大小不能在編譯的時候確定,也會分配到堆上。

如何避免

Go中的接口類型的方法調(diào)用是動態(tài)調(diào)度,因此不能夠在編譯階段確定,所有類型結構轉(zhuǎn)換成接口的過程會涉及到內(nèi)存逃逸的情況發(fā)生。如果對于性能要求比較高且訪問頻次比較高的函數(shù)調(diào)用,應該盡量避免使用接口類型。

由于切片一般都是使用在函數(shù)傳遞的場景下,而且切片在append的時候可能會涉及到重新分配內(nèi)存,如果切片在編譯期間的大小不能夠確認或者大小超出棧的限制,多數(shù)情況下都會被分配到堆上。

總結

堆上分配內(nèi)存比棧上分配內(nèi)存,開銷大很多。

變量分配在棧上需要能夠在編譯期確定他的作用域,否則會分配到堆上。

Go語言編譯器會通過變量是否被外部引用類決定是否逃逸

通過go build -gcflags '-m'命令可以觀察變量是否逃逸

不能盲目使用變量的指針作為函數(shù)參數(shù),雖然會減少復制操作,但是當參數(shù)為變量自身的時候,復制是在棧上完成的操作,開銷遠比變量逃逸后動態(tài)地在堆上分配內(nèi)存少得多。

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

相關文章

  • go語言實現(xiàn)猜數(shù)字小游戲的方法

    go語言實現(xiàn)猜數(shù)字小游戲的方法

    這篇文章主要介紹了go語言實現(xiàn)猜數(shù)字小游戲的方法,實例分析了Go語言流程判斷與處理的技巧,需要的朋友可以參考下
    2015-03-03
  • Golang pipe在不同場景下遠程交互

    Golang pipe在不同場景下遠程交互

    這篇文章主要介紹了Golang pipe在不同場景下遠程交互,pipe實現(xiàn)從一個進程重定向至另一個進程,它是雙向數(shù)據(jù)通道,用于實現(xiàn)進行間通信
    2023-03-03
  • go-cqhttp環(huán)境配置及安裝過程

    go-cqhttp環(huán)境配置及安裝過程

    這篇文章主要介紹了go-cqhttp環(huán)境配置,包括go-cqhttp安裝及簡單介紹,本文結合示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-09-09
  • Go java 算法之括號生成示例詳解

    Go java 算法之括號生成示例詳解

    這篇文章主要為大家介紹了Go java 算法之括號生成示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Golang的os標準庫中常用函數(shù)的整理介紹

    Golang的os標準庫中常用函數(shù)的整理介紹

    這篇文章主要介紹了Go語言的os標準庫中常用函數(shù),主要用來實現(xiàn)與操作系統(tǒng)的交互功能,需要的朋友可以參考下
    2015-10-10
  • golang?gorm更新日志執(zhí)行SQL示例詳解

    golang?gorm更新日志執(zhí)行SQL示例詳解

    這篇文章主要為大家介紹了golang?gorm更新日志執(zhí)行SQL示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • 一文帶你掌握Go語言運算符的使用

    一文帶你掌握Go語言運算符的使用

    運算符用于在程序運行時執(zhí)行數(shù)學或邏輯運算。Go 語言內(nèi)置的運算符有:算術運算符、關系運算符、邏輯運算符、位運算符、賦值運算符、其他運算符。本文將帶大家詳細了解一下這些運算符的使用,感興趣的可以了解一下
    2022-04-04
  • 深入探究Go語言中for?range語句

    深入探究Go語言中for?range語句

    為了更加便捷地遍歷這些數(shù)據(jù)類型,Go語言引入了for...range語句,本文將以數(shù)組遍歷為起點,逐步介紹for...range語句在不同數(shù)據(jù)類型中的應用,希望對大家有所幫助
    2023-06-06
  • Goland支持泛型了(上機實操)

    Goland支持泛型了(上機實操)

    Go的泛型不是還在設計草圖嗎?最樂觀估計也要2021年8月份。你說Go語言現(xiàn)在都沒開發(fā)好泛型,你支持這個特性有什么用呢?感興趣的朋友跟隨小編一起看看吧
    2020-12-12
  • Golang使用Gin實現(xiàn)文件上傳的示例代碼

    Golang使用Gin實現(xiàn)文件上傳的示例代碼

    本文我們主要介紹了Golang如何使用Gin實現(xiàn)文件上傳,Go標準庫net/http對文件上傳已經(jīng)提供了非常完善的支持,而Gin框架在其基礎上進一步封裝,因此使用Gin開發(fā)文件上傳功能時,只需要簡單幾行代碼便可以實現(xiàn),需要的朋友可以參考下
    2024-02-02

最新評論