内存逃逸分析

一、内存管理

内存管理其实有好多种方法,但从发展历程来看,一般是从开发者的自主管理(手动)内存到相关程序的自动管理(自动)内存。手动管理的内存优点在于可以随时管控相关的内存的状态并进行处理,但缺点是,人自主行为的不可控,特别是可能会忘记内存的回收,这就引起内存泄露。而自动管理内存就很少出现这个问题,因为GC可以定时定或者被动的来进行内存垃圾的回收。但它也有不少问题,比如可能造成程序暂停,效率低等等。
在GC过程中,内存的处理机制不同就会引出今天就分析的问题,也就是内存逃逸。

二、内存逃逸

在手动内存分配中,内存指定分配在哪儿就是在哪儿。但是在自动管理内存的带GC的程序中,事情发生了一些变化。编译器会针对具体的情况来对对象(变量)的内存分配的位置进行调整,这个过程就叫做内存逃逸。说得再简单一些,就是如果有一些对象可能分配在栈上,但编译器发现其可能被其它情况覆盖,因此将其调整到堆上。这样,其生存周期会增长。反之,从堆到栈也是如此。看一个例子:

import "fmt"

func Test(ID int) int {

	var curID int
	curID = ID

	return curID
}

func main() {
	var ID int
	fmt.Println(ID, Test(0))

}

在Goland的编译参数里增加 -gcflags "-m -l”或者直接在终端内输入命令“go run -gcflags “-m -l” main.go”
运行结果为:

# command-line-arguments
.\main.go:25:13: ... argument does not escape
.\main.go:25:13: ID escapes to heap
.\main.go:25:22: Test(0) escapes to heap

可以看到相关的内存逃逸进行了说明,有兴趣可以多根据实际情况进行测试一下例子。

三、逃逸分析

下面来分析一下具体的逃逸的情况,首先确定一下逃逸判定的规则:
1、假如函数外部没有引用,则优先放到栈中;
2、假如函数外部存在引用,则放到堆中;
3、假如栈上容纳不下,则会放到堆上
再看一下逃逸的具体场景:
1、指针逃逸
2、栈空间不足逃逸
3、动态类型逃逸
4、闭包引用对象逃逸
一般来说,栈上分配空间比在堆上分配效率高也更安全,而且栈的内存是系统自动管理不需要GC,而堆上分配的内存需要GC,而在前面分析过,所谓逃逸,其实就是在编译阶段分析是否进行堆栈内存转换。
而在实际的应用过程,内存逃逸又有一些比较典型的例子:比如函数返回一个局部变量的指针;把指针或含指针的数据发送到通道;切片上存储指针或者含指针的对象;切片底层数组的扩大分配;在接口类型上调用方法;栈空间不足;对map赋值指针类型对象等等。
那么内存逃逸有什么作用呢?
1、内存逃逸的可以减轻GC的压力,只有逃逸到堆上的才GC。
2、内存逃逸分析可以明确变量的位置并确定效率。
3、对线程而言,可以减轻同步复杂度提高运行效率。经过逃逸分析后,假如不会多线程操作会自动取消线程中的锁和相关同步机制。

四、总结

做计算机软件的,其实不外乎几个问题。CPU(多线程、多进程等)、内存(小代价大结果)、IO(尽可能速度、安全等),网络通信(分布式等),不是说其它的问题不是问题,而是最主要的就是这么几个,这里面最让人头疼不已的,内存管理这个问题肯定能拔个头筹(不认可也没办法)。其实写代码写多了,你就会发现,内存才是第一大敌人,其它都有时有晌,唯有内存的问题,常伴在身畔。
想把代码写得健壮,还是要认真看看内存如何管理好,特别是自己写代码时。不要认为有了GC,天下太平,否则,会很难看。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值