范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

一文弄清楚Golang内存逃逸

  1. 为什么要了解内存逃逸
  c/c++的programmer对于堆内存、栈内存一定非常熟悉,以为内存管理完全由使用者自己管理。Go语言的内存管理完全由Go的runtime接管,那么是不程序员就完全不用care变量是如何分配的呢?减少了gc压力。如果变量都分配到堆上,堆不像栈可以自动清理。它会引起Go频繁地进行垃圾回收,而垃圾回收会占用比较大的系统开销,甚至会导致STW(stop the world)。提高分配效率。堆和栈相比,堆适合不可预知大小的内存分配。但是为此付出的代价是分配速度较慢,而且会形成内存碎片。栈内存分配则会非常快。但当我们的服务发现性能瓶颈,要如何去定位瓶颈,让我们的程序运行的更快,就非常有必要了解Go的内存分配。2. 什么是内存逃逸
  Go语言中局部的非指针变量通常是不受GC管理的,这种Go变量的内存分配称为"栈分配",处于goroutine自己的栈中。由于Go编译器无法确定其生命周期,因此无法以这种方式分配内存的Go变量会逃逸到堆上,被称为 内存逃逸 。3. 哪些情况下会发生内存逃逸
  先来说一下通过go编译器查看内存逃逸方式go build -gcflags=-m xxx.go局部变量被返回造成逃逸package main  type User struct { 	Namestring }  func foo(s string) *User {    u := new(User)    u.Name= s    return u // 方法内局部变量返回,逃逸 }  func main() {    user := foo("hui")    user.Name= "dev" }  //# command-line-arguments //./escape.go:7:6: can inline foo //./escape.go:13:6: can inline main //./escape.go:14:13: inlining call to foo //./escape.go:7:10: leaking param: s //./escape.go:8:10: new(User) escapes to heap //./escape.go:14:13: new(User) does not escape  interface{}动态类型 逃逸package main  import "fmt"  func main() { 	name := "devhui" 	fmt.Println(name) }  //# command-line-arguments //./escape_02.go:7:13: inlining call to fmt.Println //./escape_02.go:7:13: name escapes to heap //./escape_02.go:7:13: []interface {}{...} does not escape //:1: leaking param content: .this
  很多函数的参数为interface{} 空接口类型,这些都会造成逃逸。比如func Printf(format string, a ...interface{}) (n int, err error) func Sprintf(format string, a ...interface{}) string func Fprint(w io.Writer, a ...interface{}) (n int, err error) func Print(a ...interface{}) (n int, err error) func Println(a ...interface{}) (n int, err error) 复制代码
  编译期间很难确定其参数的具体类型,也能产生逃逸func main() { 	fmt.Println("hello 逃逸") } /* 逃逸日志分析 ./main.go:5:6: can inline main ./main.go:6:13: inlining call to fmt.Println ./main.go:6:14: "hello 逃逸" escapes to heap ./main.go:6:13: []interface {} literal does not escape */ 栈空间不足逃逸package main  func main() { 	s := make([]int, 1000, 1000) 	for index, _ := range s { 		s[index] = index  	s1 := make([]int, 10000, 10000) 	for index, _ := range s1 { 		s1[index] = index 	} }
  逃逸分析:./escape_03.go:4:11: make([]int, 1000, 1000) does not escape ./escape_03.go:9:12: make([]int, 10000, 10000) escapes to heap
  s足够在栈空间分配没有逃逸;s1空间不够在栈内分配发生了逃逸。变量大小不确定(如 slice 长度或容量不定)package main  func main() { 	s := make([]int, 0, 1000) 	for index, _ := range s { 		s[index] = index 	}  	num := 1000 	s1 := make([]int, 0, num) 	for index, _ := range s1 { 		s1[index] = index 	} }
  逃逸分析:./escape_05.go:4:11: make([]int, 0, 1000) does not escape ./escape_05.go:10:12: make([]int, 0, num) escapes to heap
  s分配时cap是一个常量没有发生逃逸,s1的cap是一个变量发生了逃逸。闭包func Increase() func() int { 	n := 0 	return func() int { 		n++ 		return n 	} }  func main() { 	in := Increase() 	fmt.Println(in()) // 1 	fmt.Println(in()) // 2 }  //./escape_04.go:6:2: moved to heap: n //./escape_04.go:7:9: func literal escapes to heap //./escape_04.go:7:9: func literal does not escape //./escape_04.go:15:16: int(~R0) escapes to heap //./escape_04.go:15:13: []interface {}{...} does not escape //./escape_04.go:16:16: int(~R0) escapes to heap //./escape_04.go:16:13: []interface {}{...} does not escape //:1: leaking param content: .this 4. 如何减少逃逸局部切片尽可能确定长度或容量benchmark testimport "testing"  // sliceEscape 发生逃逸,在堆上申请切片 func sliceEscape() { 	number := 10 	s1 := make([]int, 0, number) 	for i := 0; i < number; i++ { 		s1 = append(s1, i) 	} }  // sliceNoEscape 不逃逸,限制在栈上 func sliceNoEscape() { 	s1 := make([]int, 0, 10) 	for i := 0; i < 10; i++ { 		s1 = append(s1, i) 	} }  func BenchmarkSliceEscape(b *testing.B) { 	for i := 0; i < b.N; i++ { 		sliceEscape() 	} }  func BenchmarkSliceNoEscape(b *testing.B) { 	for i := 0; i < b.N; i++ { 		sliceNoEscape() 	} } 测试结果:BenchmarkSliceEscape BenchmarkSliceEscape-10      	53271513	        22.09 ns/op BenchmarkSliceNoEscape BenchmarkSliceNoEscape-10    	187033111	         6.458 ns/op 合理选择返回值、返回指针返回指针可以避免值的拷贝,但是会导致内存分配逃逸到堆中,增加GC的负担。一般情况下,对于需要修改原对象,或占用内存比较大的对象,返回指针。对于只读或占用内存较小的对象,返回值能够获得更好的性能。benchmark testpackage escape_bench_02  import "testing"  type St struct { 	arr [100]int }  func retValue() St { 	var st St 	return st }  func retPtr() *St { 	var st St 	return &st }  func BenchmarkRetValue(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = retValue() 	} }  func BenchmarkRetPtr(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = retPtr() 	} } 测试结果BenchmarkRetValue-10            34714424                34.45 ns/op            0 B/op          0 allocs/op BenchmarkRetPtr-10               8038676               145.3 ns/op           896 B/op          1 allocs/op
  可以看到返回值更快且没有发生堆内存的分配。小的拷贝好过引用benchmark testpackage escape_bench_03  import "testing"  const capacity = 1024  func arrayFibonacci() [capacity]int { 	var d [capacity]int 	for i := 0; i < len(d); i++ { 		if i <= 1 { 			d[i] = 1 			continue 		} 		d[i] = d[i-1] + d[i-2] 	} 	return d }  func sliceFibonacci() []int { 	d := make([]int, capacity) 	for i := 0; i < len(d); i++ { 		if i <= 1 { 			d[i] = 1 			continue 		} 		d[i] = d[i-1] + d[i-2] 	} 	return d }  func BenchmarkArray(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = arrayFibonacci() 	} }  func BenchmarkSlice(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = sliceFibonacci() 	} } 测试结果:BenchmarkArray-10         346110              2986 ns/op               0 B/op          0 allocs/op BenchmarkSlice-10         389745              2849 ns/op            8192 B/op          1 allocs/op
  那么多大的变量才算是小变量呢? 对 Go 编译器而言,超过一定大小的局部变量将逃逸到堆上,不同 Go 版本的大小限制可能不一样。一般是 < 64KB,局部变量将不会逃逸到堆上。返回值使用确定的类型benchmark testpackage escape_bench_04  import "testing"  const capacity = 1024  func returnArray() [capacity]int { 	var arr [capacity]int 	for i := 0; i < len(arr); i++ { 		arr[i] = 1000 	} 	return arr }  func returnInterface() interface{} { 	var arr [capacity]int 	for i := 0; i < len(arr); i++ { 		arr[i] = 1000 	} 	return arr }  func BenchmarkReturnArray(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = returnArray() 	} }  func BenchmarkReturnInterface(b *testing.B) { 	for i := 0; i < b.N; i++ { 		_ = returnInterface() 	} } 测试结果

睡眠障碍与脑卒中的关系你知道多少呢?近年来,睡眠障碍与脑卒中风险的研究日益增多。有证据显示,睡眠障碍与高血压心力衰竭心律失常血脂紊乱等心脑血管病的危险因素有关,而这些因素都会导致脑卒中的发病明显增加。1。失眠与脑卒中孩子10岁就不喜欢和我讲话,我活成了自己最讨厌的样子关注我,并发私信社群,可加入我的育儿社群,4000家长已加入。什么是评判,什么是理解呢?下面用几幅画,做一个对比你可能很讨厌别人炫富你可能很讨厌对方的高冷你可能很讨厌一个人自以为是人到老年,如果还能做这些事情,一般都会长寿老年之后的生活并不是那么易,在现实生活当中,我们需要掌握正确的方法。想要日子过得轻松,我们就必须给自己有一个相应的规划,不要觉得你什么都可以做就可以了,其实在我们的生活当中,有一些历史,是所有强有力的生命的总和北纬30度是一条神奇的纬线,它贯穿世界四大文明古国,并在中国境内串起一系列好吃的城市。沿着这条线由东向西,你可以到舟山吃海鲜,到上海吃本帮菜,到苏州吃大闸蟹,去武汉过早,到重庆吃火人过75岁,睡觉前做好这几件事,一般都会长寿前言75岁已经算是很长寿的了,每一个人都不会嫌自己的寿命长。有些人由于自己会过日子,所以生活会很幸福,对于这样的人不管活多久都觉得是一个非常美好的事情。其实在我们的生活当中有很多事新华全媒我国在问天实验舱开展拟南芥和水稻从种子到种子全生命周期实验记者从8月29日在北京和上海同时举行的载人航天工程空间应用暨空间站高等植物培养实验阶段性进展情况介绍会上获悉,中国空间站问天实验舱内的拟南芥和水稻种子萌发已成功启动,目前生长状态良激情燃烧的岁月军区参谋长石光荣第一次授衔时为何只是大校建国后第一次授衔,石光荣才是大校,直到六十年代,他才评上了少将,为何第一次不是少将了?石光荣第一次授衔时年纪并不是特别大,四十出头,不过他已经是老革命了。剧中介绍,1950年他三十毛泽东识破了蒋介石假和谈的阴谋,决定冒着生命危险亲赴重庆谈判抗日战争胜利以后,中国人民进入了国内斗争的新时期。这一时期,国共两党各有各的打算。中国共产党要领导全国人民建立一个无产阶级领导的人民大众的新民主主义的新中国而国民党却准备发动内战,毅力号采集到曾经在水下的火星岩石,或残留外星生命遗迹美国宇航局(NASA)的毅力号漫游车采集到了曾经在水下的火星岩石标本,岩石中可能残留外星生命遗迹。据悉,NASA和欧洲航天局(ESA)正计划在2033年左右将岩石样本送回地球。毅力央视36集医疗剧亲爱的生命今晚开播,6位实力派坐镇,该火了我是接班医生,必须剖(剖腹产)。宋茜(杜帝)斩钉截铁地对着在场医生下达医疗指令。现在我说什么就是什么,你给我闭嘴!王晓晨(吴聪睿)则气场全开,直接吼出来,震得对面的医生一愣一愣的。男人过了75岁,如果对这些事情不反感,一般都会长寿前言75岁的男人早已经过了花甲之年,在这个时有很多事情其实都已经注定,不过我们不能够改变什么,但是我们好好的让自己的生活更美好,不要觉得年纪上去之后就没有意义,其实有时候年纪上去了
OPPOFindN2Flip值得入手吗?数码博主实测之后说出感受2021年,OPPO推出了第一款折叠屏手机OPPOFindN,这款折叠产品颠覆了当时主流的折叠屏定义,为折叠屏带来了黄金比例设计。一开始网络上有不理解的声音,但是随后在京东的连续多最新Nature子刊,液滴微流控相关!想象一下,如果我们身体里的细胞无法全部打乱成均匀分布会怎样?实际上,在那种情况下,基本已经只能算是一个巨型的多细胞团了,因为在生物体内,只有各种不同的细胞能够被精确的分选定位,才能酶制剂巨头诺维信和科汉森合并推动生物解决方案发展快报摘要WrapUp大企业动向BigPlayer普利制药通过合成生物学技术开发公斤级红景天苷酶制剂巨头诺维信和科汉森合并推动生物解决方案发展日本帝人子公司开发新型可降解PLA树脂材美国2022通胀高烧持续(华府观察)美国2022通胀高烧持续中新社华盛顿12月16日电题美国2022通胀高烧持续中新社记者王帆美国今年遭遇了40年来最严重的通货膨胀。广受关注的通胀指标消费者价格指数(CP超级投资人专访罗杰斯中国必将成为最成功国家,明年中国经济能更快恢复3529视频加载中编者按2022年,全球经济增长放缓,通胀高位运行,地缘政治冲突持续,美联储持续加息,全球经济复苏面临重重考验。超级投资人们如何挖掘中国机遇,如何布局全球市场?又如刚刚发布!晋江,全国第四!2022年12月16日,全国县域经济研究咨询专业智库社会组织中郡研究所完成并发布了第二十二届县域经济与县域发展监测评价报告,揭晓第二十二届全国县域经济基本竞争力百强县全国县域现代化碳金融市场概述(壹)碳金融市场形成的背景第五章碳金融市场5。1碳金融市场概述5。1。1碳金融市场形成的背景5。1。1碳金融市场形成的背景思维导图1。气候变化受到关注伴随人类社会的进步,全球经济发展迅猛,对环境和资源的压力强品种,索通发展预焙阳极行业龙头,升级循环经济的领军者(报告出品方分析师东吴证券刘博唐亚辉)1。预焙阳极行业市占率第一,近年来公司出口量占比全行业出口接近40公司成立于2003年,是一家专业从事铝用预焙阳极研发生产和销售的高新技术企业六措并举鞍本重组整合见行见效日前,鞍钢集团举办了鞍本整合重组一周年线上新闻发布会,宣布鞍本重组成功,构建了中国钢铁产业新格局,成为国企改革三年行动标志性案例。与普通的企业重组不尽相同,鞍本重组是多维度系统性的连续亏损两度陷入召回,软包电池龙头的国内困境丨智氪作者范亮编辑黄绎达封面来源视觉中国2009年,就在宁德时代成立前夕,华人科学家王瑀被我国人才计划引入国内,随王瑀一同回国的,还有其2002年创立的软包动力电池企业孚能科技。软包电池随着生活节奏的加快,这些养生知识你必须要了解大家好!因为咱们现在生活节奏加快的原因,很多人和小编一样,都明显的感觉生活压力很大,因此,身体也陆续出现了亚健康的状态。本期就让小编带你来了解一下健康养生方面的知识,有需要的朋友请