- 1、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。。
- 2、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 3、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
- 4、该文档为VIP文档,如果想要下载,成为VIP会员后,下载免费。
- 5、成为VIP后,下载本文档将扣除1次下载权益。下载后,不支持退款、换文档。如有疑问请联系我们。
- 6、成为VIP后,您将拥有八大权益,权益包括:VIP文档下载权益、阅读免打扰、文档格式转换、高级专利检索、专属身份标志、高级客服、多端互通、版权登记。
- 7、VIP文档为合作方或网友上传,每下载1次, 网站将根据用户上传文档的质量评分、类型等,对文档贡献者给予高额补贴、流量扶持。如果你也想贡献VIP文档。上传文档
第
一文带你轻松理解Go中的内存逃逸问题
目录内存逃逸是什么内存逃逸危害内存逃逸现象逃逸分析原则内存逃逸解决具体案例参数为interface类型会逃逸变量在函数外部有引用会逃逸变量占用内存较大时会逃逸变量大小不确定时会逃逸
内存逃逸是什么
在程序中,每个函数块都会有自己的内存区域用来存自己的局部变量(内存占用少)、返回地址、返回值之类的数据,这一块内存区域有特定的结构和寻址方式,寻址起来十分迅速,开销很少。这一块内存地址称为栈。栈是线程级别的,大小在创建的时候已经确定,当变量太大的时候,会逃逸到堆上,这种现象称为内存逃逸。简单来说,局部变量通过堆分配和回收,就叫内存逃逸。
内存逃逸危害
堆是一块没有特定结构,也没有固定大小的内存区域,可以根据需要进行调整。全局变量,内存占用较大的局部变量,函数调用结束后不能立刻回收的局部变量都会存在堆里面。变量在堆上的分配和回收都比在栈上开销大的多。对于go这种带GC的语言来说,会增加gc压力,同时也容易造成内存碎片。
内存逃逸现象
向channel发送指针数据。因为在编译时,不知道channel中的数据会被哪个goroutine接收,因此编译器没法知道变量什么时候才会被释放,因此只能放入堆中。局部变量在函数调用结束后还被其他地方使用,比如函数返回局部变量指针或闭包中引用包外的值。因为变量的生命周期可能会超过函数周期,因此只能放入堆中。在slice或map中存储指针。比如[]*string,其后面的数组可能是在栈上分配的,但其引用的值还是在堆上。切片扩容后长度太大,导致栈空间不足,逃逸到堆上。在interface类型上调用方法。在interface类型上调用方法时会把interface变量使用堆分配,因为方法的真正实现只能在运行时知道。
逃逸分析原则
编译阶段无法确定的参数,会逃逸到堆上;变量在函数外部存在引用,会逃逸到堆上;不存在引用,则会继续在栈上;变量占用内存较大时,会逃逸到堆上;
内存逃逸解决
对于小型的数据,使用传值而不是传指针,避免内存逃逸。避免使用长度不固定的slice切片,在编译期无法确定切片长度,只能将切片使用堆分配。interface调用方法会发生内存逃逸,在热点代码片段,谨慎使用。
避免内存逃逸需要遵循如下两个原则:指向栈对象上的指针不能被存储到堆中。指向栈对象上的指针不能超过该栈对象的声明周期。
具体案例
参数为interface类型会逃逸
下面通过举例,来进一步论证逃逸分析的原则,加深一下理解
我们可以使用这个命令gobuild-gcflags-m-m-lgo文件名,来查看逃逸分析的结果。
funcmain(){
num:=1
fmt.Println(num)
}
原因分析:
funcPrintln(a...interface{})(nint,errerror),这个函数的入参是interface类型,编译阶段无法确定其具体的参数类型,所以内存分配到堆上
变量在函数外部有引用会逃逸
funcmain(){
_=test()
functest()*int{
num:=10
returnnum
}
原因分析:
变量num在函数外部存在引用,函数退出时栈中的内存(栈帧)已经释放,但引用已经被返回,如果通过引用地址取值,在栈中是取不到值的,所以Go为了避免这个情况,会将内存分配到堆上。
变量占用内存较大时会逃逸
funcmain(){
//不会逃逸
s1:=make([]int,10,10)
fori:=0;ii++{
s1[i]=i
//会逃逸
s2:=make([]int,10000,10000)
fori:=0;i10000;i++{
s2[i]=i
}
原因分析:
切片容量过大时,会产生逃逸,内存分配到堆上;容量小时,不会逃逸,内存分配依赖在栈上。
变量大小不确定时会逃逸
funcmain(){
num:=10
s:=make([]int,num,num)
fori:=0;inum;i++{
s[i]=i
}
原因分析:
切片的长度和容量,虽然通过声明的变量num来指定了,但在编译阶段是未知的,并不确定num的具体值,所以会逃逸,将内存分配到堆上。
您可能关注的文档
最近下载
- 超详细AMS2750E中文版.pdf
- 2021年北京市第一中西医结合医院医护人员招聘试题及答案解析.docx VIP
- 2024年北京市第一中西医结合医院人员招聘备考试题及答案解析.docx VIP
- 2022年北京市第一中西医结合医院医护人员招聘考试试题及答案解析.docx VIP
- 2022年北京市第一中西医结合医院医护人员招聘模拟试题及答案解析.docx VIP
- 压合机及回流线简介.ppt VIP
- 2023年专升本考试英语300个必背词汇.pdf VIP
- 高职养生康复技术教案.docx VIP
- 2024年北京市第一中西医结合医院人员招聘模拟试题及答案解析.docx VIP
- 2024年北京市第一中西医结合医院人员招聘备考题库及答案解析.docx VIP
文档评论(0)