一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

golang變量逃逸分析

 鳳凰苑兇真 2016-12-09

看到這篇博文: http://www./go-allocated-on-heap-or-stack.md ,于是想深入探究一下。

既然fmt.Println會使a、b逃逸,println不會,那就先從fmt.Println入手。

把fmt.Println的相關(guān)源碼復(fù)制到同一個文件內(nèi),以讓編譯器給出具體的逃逸分析報告。 就是src/fmt/print.go和src/fmt/format.go兩個文件的內(nèi)容。

用go tool compile -m生成報告,有幾千行,分析之。

先找到定義a變量的那一行,然后往上看:

a.go:1272: reflect.t·2 escapes to heap
a.go:1265: leaking param content: a
a.go:1265: leaking param content: p
a.go:1265: leaking param content: p
a.go:1265: leaking param: p
a.go:1265: leaking param content: a
a.go:1268: (*pp).doPrint p.fmt does not escape
a.go:1272: (*pp).doPrint &reflect.i·2 does not escape
a.go:1274: (*pp).doPrint p.buf does not escape
a.go:1280: (*pp).doPrint p.buf does not escape
a.go:150: (*pp).free ignoring self-assignment to p.buf
a.go:153: ppFree escapes to heap
a.go:153: p escapes to heap
a.go:145: leaking param: p
a.go:256: leaking param content: a
a.go:256: leaking param: w
a.go:268: os.Stdout escapes to heap
a.go:267: leaking param content: a
a.go:17: b escapes to heap
a.go:15: moved to heap: a

從最下一句往上分析:

a被移到堆上
因為b逃逸到堆上
Println的a參數(shù)(就是傳入的b變量組成的[]interface{})的內(nèi)容泄漏
這個泄漏不是指內(nèi)存泄漏,而是指該傳入?yún)?shù)的內(nèi)容的生命期,超過函數(shù)調(diào)用期,也就是函數(shù)返回后,該參數(shù)的內(nèi)容仍然存活
os.Stdout逃逸到堆上
Fprintln的w、a參數(shù)都泄漏
*pp.free的p參數(shù)(就是receiver)泄漏
該receiver逃逸到heap
ppFree逃逸到heap(這是個全局變量)

把ppFree.Put(p))這行注釋掉(因為可能是它引用了最初傳入的參數(shù)),然后重新go tool compile -m。仍然被移動到堆上。

繼續(xù)往上分析,然后居然發(fā)現(xiàn)這條:

a.go:1272: reflect.t·2 escapes to heap

對應(yīng)的代碼是:

isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
reflect.TypeOf(arg).Kind()居然會導(dǎo)致arg逃逸到堆上。可以用下面的程序驗證(TypeOf不會,程序略):
package main

import "reflect"

func main() {
    a := &struct{}{}
    _ = reflect.TypeOf(a).Kind()
}

于是再去看reflect.Type.Kind()的代碼,是這樣的:

func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }

于是問題變成,為什么reflect.TypeOf(arg).Kind()會導(dǎo)致arg逃逸。

按照前面的辦法,復(fù)制reflect包的內(nèi)容到文件里的話,會比較麻煩,因為有些函數(shù)是定義在runtime包里的。 所以只要一些骨架,能重現(xiàn)就行:

package main

import (
    "unsafe"
)

type Kind uint

const kindMask = (1 << 5) - 1

type Type interface {
    Kind() Kind
}

func TypeOf(i interface{}) Type {
    eface := *(*emptyInterface)(unsafe.Pointer(&i))
    return toType(eface.typ)
}

func toType(t *rtype) Type {
    if t == nil {
        return nil
    }
    return t
}

type rtype struct {
    kind uint8 // enumeration for C
}

func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }

type emptyInterface struct {
    typ  *rtype
    word unsafe.Pointer
}

func main() {
    a := &struct{}{}
    _ = TypeOf(a).Kind()
}

上面代碼的go tool compile -m 結(jié)果是:

a.go:20: can inline toType
a.go:15: can inline TypeOf
a.go:17: inlining call to toType
a.go:31: can inline (*rtype).Kind
a.go:40: inlining call to TypeOf
a.go:40: inlining call to toType
a.go:17: t escapes to heap
a.go:15: leaking param: i to result ~r1 level=0
a.go:16: TypeOf &i does not escape
a.go:24: t escapes to heap
a.go:20: leaking param: t to result ~r1 level=0
a.go:31: (*rtype).Kind t does not escape
a.go:40: t escapes to heap
a.go:40: a escapes to heap
a.go:39: &struct {} literal escapes to heap
a.go:40: main &i does not escape
:1: leaking param: .this

a在堆上分配了。

(分析一小時后……)

結(jié)論是,調(diào)用interface的方法會導(dǎo)致變量被移到堆上。將上面main里的改成 _ = TypeOf(a).(*rytpe).Kind(),a就不會逃逸了。

同理,下面的程序:

package main

type T interface {
    Foo()
}

type S struct{}

func (s *S) Foo() {}

func main() {
    s := new(S)
    T(s).Foo()
}

s會移到堆上。 所以問題變成,為什么調(diào)用接口方法會使引用的變量被放到堆上。

在repo搜索了下,發(fā)現(xiàn)是個known issue: https://github.com/golang/go/issues/7213 ,而且缺少關(guān)愛。 可能轉(zhuǎn)到SSA后端后,會有更好的優(yōu)化吧。 所以現(xiàn)在想優(yōu)化掉這個的話,只能避免使用接口方法了。

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    成年女人午夜在线视频| 91精品国自产拍老熟女露脸| 久草视频在线视频在线观看| 爱在午夜降临前在线观看| 久久国产亚洲精品赲碰热| 亚洲一区二区三区精选| 日韩人妻中文字幕精品| 国产精品香蕉免费手机视频| 欧美日韩精品一区免费| 免费黄色一区二区三区| 好吊视频一区二区在线| 日韩欧美好看的剧情片免费| 国产一区欧美一区日本道| 亚洲最大的中文字幕在线视频| 国产又粗又猛又爽色噜噜| 国产成人国产精品国产三级| 欧美一区二区日韩一区二区| 久草视频这里只是精品| 精品人妻少妇二区三区| 亚洲欧美视频欧美视频| 欧美日韩乱一区二区三区| 麻豆剧果冻传媒一二三区| 亚洲国产av在线观看一区| 日本理论片午夜在线观看| 99久久人妻精品免费一区| 日韩人妻毛片中文字幕| 国内外免费在线激情视频| 国产国产精品精品在线| 欧美国产极品一区二区| 国产精品亚洲欧美一区麻豆| 美女被后入福利在线观看| 国产av精品高清一区二区三区| 日韩在线精品视频观看| 大香蕉伊人一区二区三区| 成人日韩在线播放视频| 免费在线观看激情小视频 | 国产白丝粉嫩av在线免费观看 | 殴美女美女大码性淫生活在线播放| 日韩一区二区三区在线欧洲| 97人摸人人澡人人人超碰| 国产一区二区三区四区免费|