Go中的逃逸分析

一、什么是逃逸分析

在函数内部定义了一个局部变量,然后返回这个局部变量的地址(指针)。由于这些局部变量是在栈上分配的(静态内存分配),一旦函数执行完毕,变量占据的内存被销毁,任何对这个返回值的动作(如解引用),都将扰乱程序的运行,甚至导致程序直接崩溃。比如下面的这段代码:

int *foo ( void)   
{     
int t = 3;
return &t;
} 

解决办法:在函数内部使用new函数构造一个变量(动态内存分配),然后返回此变量的地址。因为变量是在堆上创建的,所以函数退出时不会被销毁。但是,这样就行了吗?new出来的对象该在何时何处地delete呢?调用者可能忘记delete或者直接拿掉返回值传给其他函数,之后就再也不能delete它了,也就是发生可内存泄露。

而这一切在Go语言中就大不相同了。像上面示例的C++代码放到Go里,没有任何问题。

通俗来讲,当一个对象的指针被多个方法或线程引用时,我们称这个指针发生了逃逸。

更简单的来说,逃逸分析决定了一个变量是分配在堆上还是分配在栈上。

二、为什么需要逃逸分析

逃逸分析这种操作把变量合理的分配到了它该去的地方,”找准自己的位置“。即使你是用new申请的内存,如果我发现你竟然在退出函数后没有用了,那么就把你丢到栈上,毕竟栈上的内存分配比堆上快很多;反之,即使你表面上只是一个普通的变量,但是经过逃逸分析后发现退出函数之后还有其他地方在引用,那我就把你分配到堆上。真正的按需分配,提前实现共产主义

如果变量都分配到堆上,堆不像栈可以自动清理。它会引起go频繁的进行垃圾回收,二垃圾回收会占用比较大的系统开销(占用cpu容量的25%)。

通过逃逸分析,可以尽量把那些不需要分配到堆上的变量直接分配到栈上,堆上的变量少了,会减轻分配堆内存的开销,同时减轻gc的压力,提高程序的原型速度。

三、Go中的逃逸准则

Go中逃逸分析最基本的原则是:如果一个函数返回对一个变量的引用,那么它就发生逃逸。
简单来说,编译器会根据变量是否被外部引用来决定是否逃逸:

1、如果函数外部没有引用,则优先放到栈中;

2、如果函数外部存在引用,则必定放到堆中;

如何查看是否发生逃逸

olang提供了编译的参数让我们可以直观地看到变量是否发生了逃逸,只需要在go build时指定

go build -gcflags '-m -l' main.go

除了使用编译参数之外,我们还可以使用一种更底层的,更硬核,也更准确的方式来判断一个对象是否逃逸,那就是:直接看汇编!

go tool compile -S
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值