Golang Go语言中的一个小疑惑请教

发布于 1周前 作者 ionicwang 来自 Go语言

Golang Go语言中的一个小疑惑请教

golang 里面,下面的两个函数,是不是第 2 种更加 GC 友好一些呢?


func aToB (a* A) *B {

}

func aToB (a* A, b *B) {

}

根据我粗浅的认知,第一种写法是不是会出现逃逸,后面还得 GC 去回收呢?

谢谢。

17 回复

一样的,你外面传到里面,和里面返回到外面,不都是逃逸吗。你自己用逃逸分析试试看。实践出真知嘛

更多关于Golang Go语言中的一个小疑惑请教的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


有啥区别这样



第二种情况 b 完全可以走栈内存啊。

除非是 unmarshal ,基本没见到第二种写法的

b 可能在函数里被赋值给了一个全局变量

某些时候分配在 caller (或者 caller 的 caller……)的 stack 上确实可以避免逃逸到 heap 上,我猜你指的是这个意思。

https://gist.github.com/lujjjh/02d89fd848ee72ce3dd47156fc97c184

理论上编译器应该可以自动优化某些场景(比如上面在函数内联的时候编译器已经能做到避免逃逸到 heap 了),但是在不内联的时候就比较麻烦了,似乎得像真泛型一样为不同场景的 caller 生成不同的函数实现。

第二种不好 hold 住返回的 b 为 nil 的 case

b 是可以永远不为 nil 的,因为这是类似 C/C++那套,函数不帮你分配对象,你得自己分配好传进去。至于如何判断错误,加个返回值作为判断操作是否成功就好了。

#3
在栈上除非是简单的基本类型,那么在返回的时候也就相当于一个赋值。
如果是对象的话,那肯定是在堆上的,栈上只是一个地址,那么你两种写法应该是一样的。
第一种写法是自己创建一个对象,把地址赋值出去,第二种是外面创建好对象,地址赋值到栈上再传进来(传进来也是一个赋值复制的过程)。

都可以。
不过第二个要么返回 bool ,要么返回 error ,更好一点

实际上还有第三种写法:既接受入参又返回出参,允许入参 nil 表示内部 allocate ,常见于[]byte

你说的对,当指针作为返回值,一定发生逃逸。如果是传值进来,则是可能发生逃逸,所以相对来说更 GC 友好一些,但其实这么对比没什么意义。

而且说实话,这两种写法都不太符合 go 的哲学?
同 Trim21 所说,除非 Unmarshal ,基本不会使用 c++ 的那种写法,在 go 上面开起来就没那么优雅。
如果真要阻止逃逸那大部分会直接写 func aToB (a A) b B ,用内存 copy 开销来规避逃逸。

func aToB (a* A, b *B) {}

这种写法,只是更不容易发生逃逸,但是但凡你函数内用到任意一个会发生逃逸的函数,你前面的工作就全白费了,比如 fmt.Printf(b),所以实际写的时候不会在这两种写法上纠结,因为没法保证一定不逃逸。

是的, 第二种不一定发生逃逸.

但是除非有理由, 我个人更推荐第一种写成 func aToB (a* A) B {}

b 原本的值还是会逃逸的吧,进入栈内的是地址,差距不大

当然,我很乐意帮你解答关于Go语言的小疑惑。

你好!很高兴你对Go语言感兴趣。Go语言作为一种现代编程语言,以其简洁、高效和并发处理能力而著称。针对你的疑惑,虽然你没有具体说明疑惑的内容,但我可以根据一些常见的Go语言问题给出一些可能的解答方向:

  1. 并发编程:如果你对Go的goroutines和channels有疑问,它们是实现并发编程的关键。goroutines是轻量级的线程,而channels则用于在goroutines之间传递数据。

  2. 接口:Go语言的接口非常灵活,不需要显式实现。只要一个类型提供了接口中定义的所有方法,它就隐式地实现了该接口。

  3. 错误处理:Go语言通过返回错误值(通常是error类型的值)来处理错误,而不是使用异常机制。这要求程序员显式地检查和处理错误。

  4. 内存管理:Go语言有自动的内存管理机制(垃圾回收),但了解何时会触发垃圾回收以及如何优化内存使用仍然很重要。

  5. 标准库:Go语言的标准库非常强大,涵盖了网络编程、文件操作、加密解密等多个方面。

如果你有更具体的问题,比如关于某个特定函数、方法或特性的疑惑,请提供更详细的信息,我会尽力给出更准确的解答。希望这些建议能对你有所帮助!

回到顶部