溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

?golang面試題之內存逃逸的示例分析

發(fā)布時間:2021-04-16 10:32:00 來源:億速云 閱讀:180 作者:小新 欄目:編程語言

這篇文章將為大家詳細講解有關golang面試題之內存逃逸的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

問題

知道golang的內存逃逸嗎?什么情況下會發(fā)生內存逃逸?

怎么答

golang程序變量會攜帶有一組校驗數據,用來證明它的整個生命周期是否在運行時完全可知。如果變量通過了這些校驗,它就可以在棧上分配。否則就說它 逃逸 了,必須在堆上分配。

能引起變量逃逸到堆上的典型情況

  • 在方法內把局部變量指針返回 局部變量原本應該在棧中分配,在棧中回收。但是由于返回時被外部引用,因此其生命周期大于棧,則溢出。

  • 發(fā)送指針或帶有指針的值到 channel 中。 在編譯時,是沒有辦法知道哪個 goroutine 會在 channel 上接收數據。所以編譯器沒法知道變量什么時候才會被釋放。

  • 在一個切片上存儲指針或帶指針的值。 一個典型的例子就是 []*string 。這會導致切片的內容逃逸。盡管其后面的數組可能是在棧上分配的,但其引用的值一定是在堆上。

  • slice 的背后數組被重新分配了,因為 append 時可能會超出其容量( cap )。 slice 初始化的地方在編譯時是可以知道的,它最開始會在棧上分配。如果切片背后的存儲要基于運行時的數據進行擴充,就會在堆上分配。

  • 在 interface 類型上調用方法。 在 interface 類型上調用方法都是動態(tài)調度的 —— 方法的真正實現只能在運行時知道。想像一個 io.Reader 類型的變量 r , 調用 r.Read(b) 會使得 r 的值和切片b 的背后存儲都逃逸掉,所以會在堆上分配。

舉例

  • 通過一個例子加深理解,接下來嘗試下怎么通過 go build -gcflags=-m 查看逃逸的情況。

package main
import "fmt"
type A struct {
    s string
}
// 這是上面提到的 "在方法內把局部變量指針返回" 的情況
func foo(s string) *A {
    a := new(A) 
    a.s = s
    return a //返回局部變量a,在C語言中妥妥野指針,但在go則ok,但a會逃逸到堆
}
func main() {
    a := foo("hello")
    b := a.s + " world"
    c := b + "!"
    fmt.Println(c)
}

執(zhí)行go build -gcflags=-m main.go

go build -gcflags=-m main.go
# command-line-arguments
./main.go:7:6: can inline foo
./main.go:13:10: inlining call to foo
./main.go:16:13: inlining call to fmt.Println
/var/folders/45/qx9lfw2s2zzgvhzg3mtzkwzc0000gn/T/go-build409982591/b001/_gomod_.go:6:6: can inline init.0
./main.go:7:10: leaking param: s
./main.go:8:10: new(A) escapes to heap
./main.go:16:13: io.Writer(os.Stdout) escapes to heap
./main.go:16:13: c escapes to heap
./main.go:15:9: b + "!" escapes to heap
./main.go:13:10: main new(A) does not escape
./main.go:14:11: main a.s + " world" does not escape
./main.go:16:13: main []interface {} literal does not escape
<autogenerated>:1: os.(*File).close .this does not escape
  • ./main.go:8:10: new(A) escapes to heap 說明 new(A) 逃逸了,符合上述提到的常見情況中的第一種。

  • ./main.go:14:11: main a.s + " world" does not escape 說明 b 變量沒有逃逸,因為它只在方法內存在,會在方法結束時被回收。

  • ./main.go:15:9: b + "!" escapes to heap 說明 c 變量逃逸,通過fmt.Println(a ...interface{})打印的變量,都會發(fā)生逃逸,感興趣的朋友可以去查查為什么。

關于“golang面試題之內存逃逸的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI