首頁  >  文章  >  後端開發  >  golang面試題之簡單聊聊記憶體逃脫?

golang面試題之簡單聊聊記憶體逃脫?

藏色散人
藏色散人轉載
2021-04-16 10:02:411771瀏覽

以下由golang教學專欄跟大家介紹golang面試題:簡單聊聊記憶體逃脫? ,希望對需要的朋友有幫助!

golang面試題之簡單聊聊記憶體逃脫?

問題

知道golang的記憶體逃脫嗎?什麼情況下會發生記憶體逃脫?

怎麼答

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

能造成變數逃逸到堆疊上的典型情況

  • #在方法內把局部變數指標回傳 局部變數原本應該在棧中分配,在棧中回收。但是由於返回時被外部引用,因此其生命週期大於堆疊,則溢出。
  • 將指標或帶有指標的值傳送到 channel 中。 在編譯時,是沒有辦法知道哪個 goroutine 會在 channel 上接收資料。所以編譯器沒辦法知道變數什麼時候才會被釋放。
  • 在一個切片上儲存指標或帶指標的值。 典型的例子就是 []*string 。這會導致切片的內容逃逸。儘管其後面的數組可能是在堆疊上分配的,但其引用的值一定是在堆上。
  • slice 的背後陣列被重新分配了,因為 append 時可能會超出其容量( cap )。 slice 初始化的地方在編譯時是可以知道的,它最開始會在堆疊上分配。如果切片背後的儲存要基於運行時的資料進行擴充,就會在堆上分配。
  • 在 interface 類型上呼叫方法。 在 interface 類型上呼叫方法都是動態調度的 —— 方法的真正實作只能在執行時知道。想像一個 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)
}

執行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{})列印的變量,都會發生逃逸,有興趣的朋友可以去檢查為什麼。
  • 以上運算其實就叫逃逸分析下篇文章,跟大家聊聊怎麼用一個比較trick的方法讓變數不逃逸。方便大家在面試官面前秀一波
#

以上是golang面試題之簡單聊聊記憶體逃脫?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:segmentfault.com。如有侵權,請聯絡admin@php.cn刪除