真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

如何理解golang逃逸分析

本篇內(nèi)容介紹了“如何理解golang逃逸分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、梅列網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、HTML5建站、商城網(wǎng)站定制開發(fā)、集團公司官網(wǎng)建設(shè)、外貿(mào)網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為梅列等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。

背景

最近想要將 protobuf 變量和之前設(shè)計的數(shù)據(jù)對象整合起來,維護在內(nèi)存中,以減少內(nèi)存申請和 GC 的性能損耗。

feature or bug,gogoproto 解碼疑惑

由于 gogoproto 在 unmarshal 時不保證輸入和輸出一致,作為結(jié)果的指針變量和輸入的字節(jié)切片可能不一致(比如說,在 unmarshal slice 時沒有 reset 操作)。我們需要對這個指針變量進(jìn)行重置,pb 生成文件的 reset 實現(xiàn)方法如下。

func (m *Data) Reset() { *m = Data{} }

在看到 Data{} 時我陷入了疑惑,按我的理解,這一步是需要申請內(nèi)存的。那么如此一來,我們在將某個 pb 變量拋入內(nèi)存時不可避免的還是需要申請內(nèi)存,這樣本次的研發(fā)需求好像失去了意義。

我的第一反應(yīng)是,這是 gogoproto 的問題,也許官方 go proto 不是這樣的??墒侵匦律珊蟀l(fā)現(xiàn) reset 方法實現(xiàn)并沒有什么區(qū)別。只不過官方 go proto 會在 unmarshal 時主動 reset

那么,難道一開始的方向就錯了嗎?啊頭禿。

柳暗花明又一村

不死心的我開始看各種文檔,包括 gogoproto 的各種插件,可惜并沒有找到有用的內(nèi)容。接著我又開始看官方 proto 文檔。。。

這時我發(fā)現(xiàn)了一點蛛絲馬跡。

在日常使用 protobuf 時,如果不復(fù)用舊的變量,我們一般會

  1. 聲明指針變量,data := &pb.Data{};

  2. 解碼,proto.Unmarshal(bytes, data)。

顯然,第一步是需要申請內(nèi)存。而按照 go proto 的源碼,unmarshal 時的 reset 操作又會申請一次內(nèi)存,難道 Google 會允許這種性能損耗?

真的嗎,我不信。

逃逸分析入門

想的太多,不如寫個 benchmark 試一下。(小心 microbenchmark 的一些坑)

benchmark

package main

import (
	"testing"
)

type boy struct {
	name string
	age  int
}

var b1 = &boy{}
var b2 = &boy{}

func Benchmark_1(b *testing.B) {

	for i := 0; i < b.N; i++ {
		temp := &boy{}
		b1 = temp
	}
}

func Benchmark_2(b *testing.B) {

	for i := 0; i < b.N; i++ {
		temp := &boy{}
		*b1 = *temp
	}
}

func Benchmark_3(b *testing.B) {

	for i := 0; i < b.N; i++ {
		temp := &boy{}
		*b1 = *temp
		b2 = temp
	}
}

結(jié)果如下。

goos: linux
goarch: amd64
pkg: bible
Benchmark_1-4   	29142411	        42.2 ns/op	      32 B/op	       1 allocs/op
Benchmark_2-4   	1000000000	         0.711 ns/op	       0 B/op	       0 allocs/op
Benchmark_3-4   	28474614	        39.5 ns/op	      32 B/op	       1 allocs/op
PASS
ok  	bible	3.258s

結(jié)果是一目了然的,temp := &boy{} 確實沒有重復(fù)申請內(nèi)存。

編譯報告

到此,只需要逐個分析就好。首先打開編譯報告看一下。

go build -gcflags "-m -m"

var b1 = &boy{}
//go:noinline
func main() {
	temp := &boy{}
	// &boy literal escapes to heap:
	//   flow: temp = &{storage for &boy literal}:
	//     from &boy literal (spill) at ./main.go:12:10
	//     from temp := &boy literal (assign) at ./main.go:12:7
	//   flow: {heap} = temp:
	//     from b1 = temp (assign) at ./main.go:13:5
	// &boy literal escapes to heap
	b1 = temp
}

新創(chuàng)建的 &boy{} 被全局變量引用,于是逃逸到堆上,成為動態(tài)變量,無法被重復(fù)利用。

var b1 = &boy{}
//go:noinline
func main() {
	temp := &boy{}
	// &boy literal does not escape
	*b1 = *temp
}

*b1 = *temp 僅僅是賦值操作,新創(chuàng)建的 &boy{} 沒有被引用,留在棧上,后續(xù)被重復(fù)利用。

匯編分析

如何理解golang逃逸分析

“如何理解golang逃逸分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!


本文名稱:如何理解golang逃逸分析
鏈接URL:http://weahome.cn/article/jpigcd.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部