[go语言应用一句话] 内存管理-变量逃逸及踩坑历程

1、Go语言中的变量逃逸指的是在编译阶段,编译器将一个栈上的局部变量转移到堆上分配内存。
(1)c语言中函数内的局部变量在栈上分配内存,malloc动态申请的内存在堆上。
(2)而在go语言中,在码小范围代码时不需要操这个心了,但要写出高效、稳定的程序还是必须要熟悉内存的分配规则。
(3)变量逃逸是go的编译器在编译阶段做的事情。
(4)编译器会判断如果局部变量在它的作用域之外被引用,则会将该局部变量的内存转义到堆上。
(5)程序员不需要主动释放堆上的内存,那堆上的内存如何释放?go的垃圾回收机制会周期性的回收没有引用的内存。
(6)周期的被动释放,也说明堆上的无引用的内存释放不像c/c++是实时的。相对c/c++,它会消耗更多内存资源。

2、踩坑历程
(1)for循环里的错误变量引用,“自以为是”的变量逃逸,错误代码:

	// ItemMap 是 ItemMap map[string]*Item类型。
	for _, v := range input.DeviceList.Item {
		dev.ItemMap[v.DeviceID] = &v
		dev.ItemCount += 1
	}

上述代码想要遍历 input.DeviceList.Item 并把 成员插入 dev.ItemMap。这里的错误在于for的每一次循环,v 的地址并没有变化,把 &v赋值给dev.ItemMap[v.DeviceID] 最终会导致 dev.ItemMap[v.DeviceID]的每一个成员都指向了同一块内存,虽然这块内存由栈逃逸到了堆,但只有一个v的实例。

潜意识里会错误的认为 for _, v := range input.DeviceList.Item {} 每次循环 v 都是新的内存,但事实是本次所有循环内都没跳出v的作用域,所以没不会申请新的内存。

正确的代码应该是重新申请一块内存,device的内存会逃逸到堆上:

	for _, v := range input.DeviceList.Item {
		device := v  // 重新申请一块内存,device的内存会逃逸到堆上。
		dev.ItemMap[v.DeviceID] = &device
		dev.ItemCount += 1
	}

(2)待补充

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_44764006

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值