当前位置: 首页 > 科技观察

Go语言内存逃逸之谜

时间:2023-03-16 13:54:01 科技观察

本文转载自微信公众号《后端技术罗盘》,作者大白。转载本文请联系后台技术指南针公众号。我们在高中时学过一些天体物理学的知识,比如常见的三种宇宙速度:第一宇宙速度:航天器脱离地面绕地球运动的最小速度:7.9km/s第二宇宙速度:航天器逃离地球航天器最小速度:11.18km/s第三宇宙速度:航天器逃离太阳系最小速度:16.64km/s了解了航天器的逃逸行为后,我们有一些特别的东西今天:记忆逃脱。通过本文,你将了解到:C/C++内存布局与栈Go内存逃逸与逃逸分析内存逃逸总结Part1C/C++内存布局与栈这应该是一道出现频率很高的面试题。C/C++是一种静态强类型语言。编译成二进制文件后,整个程序在运行时的内存空间分为:关于程序本身的一些信息,我们来看一下用户空间的布局:堆和栈的主要特点:栈区(Stack):由编译器自动分配和释放,存放函数参数值,局部变量值等十进制KB~几MB堆区(Heap):C/C++没有GC机制,一般申请堆内存并由程序员发布。空间大,能不能用好,就看使用者的水平了。Go语言和C语言的关系很深很深,C语言面临的问题,Go也会面临,比如:变量的内存分配。在C语言中,程序员需要根据需要来决定是使用堆还是栈。栈内存完全由OS负责,而堆内存则需要通过malloc/new等函数显式调用,并相应调用free/delete来释放。Go语言对堆内存管理有GarbageCollection机制,没有像malloc/new这样的堆内存分配关键字。栈内存的分配和释放开销很小,对于Go来说堆内存的开销远高于栈内存。如果你写过C/C++,你就会知道Part2Go的内存逃逸和逃逸分析。在函数内部声明一个局部变量,然后返回它的指针。如果在外部调用会报错:#includeusingnamespacestd;int*getValue(){intval=10086;return&val;}intmain(){cout<<*getValue()<:1:(*File).close.thisdoesnotescape我们可以看到“escapestoheap”,确实发生了内存逃逸,由于堆栈空间不足,应该从堆栈上逃逸到堆中。对于64位Linux系统,堆栈大小一般为8MB。在Go中,每个goroutine的初始堆栈大小为2KB。goroutine运行过程中,栈大小可能会有所不同,但不会超过OS对线程栈大小的限制。我在网上找了个例子用mac运行:packagemainimport"math/rand"funcgenerate8191(){nums:=make([]int,8191)//<64KBfori:=0;i<8191;i++{nums[i]=rand.Int()}}funcgenerate8192(){nums:=make([]int,8192)//=64KBfori:=0;i<8192;i++{nums[i]=rand.Int()}}funcgenerate(nint){nums:=make([]int,n)//不确定大小fori:=0;i