请教一个 golang 的小疑惑

2022-01-09 21:40:40 +08:00
 wheeler

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


func aToB (a* A) *B {

}

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

}

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

谢谢。

3170 次点击
所在节点    Go 编程语言
16 条回复
Glauben
2022-01-09 22:20:59 +08:00
一样的,你外面传到里面,和里面返回到外面,不都是逃逸吗。你自己用逃逸分析试试看。实践出真知嘛
wunonglin
2022-01-09 22:25:41 +08:00
有啥区别这样
wheeler
2022-01-09 22:42:00 +08:00
@2435043xia
@wunonglin
第二种情况 b 完全可以走栈内存啊。
Trim21
2022-01-09 23:41:02 +08:00
除非是 unmarshal ,基本没见到第二种写法的
lance6716
2022-01-09 23:46:33 +08:00
b 可能在函数里被赋值给了一个全局变量
lujjjh
2022-01-10 00:28:53 +08:00
某些时候分配在 caller (或者 caller 的 caller……)的 stack 上确实可以避免逃逸到 heap 上,我猜你指的是这个意思。

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

理论上编译器应该可以自动优化某些场景(比如上面在函数内联的时候编译器已经能做到避免逃逸到 heap 了),但是在不内联的时候就比较麻烦了,似乎得像真泛型一样为不同场景的 caller 生成不同的函数实现。
katsusan
2022-01-10 01:23:13 +08:00
@wheeler 第二种不好 hold 住返回的 b 为 nil 的 case
neoblackcap
2022-01-10 03:12:05 +08:00
@katsusan b 是可以永远不为 nil 的,因为这是类似 C/C++那套,函数不帮你分配对象,你得自己分配好传进去。至于如何判断错误,加个返回值作为判断操作是否成功就好了。
jinliming2
2022-01-10 09:30:38 +08:00
@wheeler #3
在栈上除非是简单的基本类型,那么在返回的时候也就相当于一个赋值。
如果是对象的话,那肯定是在堆上的,栈上只是一个地址,那么你两种写法应该是一样的。
第一种写法是自己创建一个对象,把地址赋值出去,第二种是外面创建好对象,地址赋值到栈上再传进来(传进来也是一个赋值复制的过程)。
fgwmlhdkkkw
2022-01-10 09:33:14 +08:00
都可以。
不过第二个要么返回 bool ,要么返回 error ,更好一点
mcfog
2022-01-10 10:07:39 +08:00
实际上还有第三种写法:既接受入参又返回出参,允许入参 nil 表示内部 allocate ,常见于[]byte
SSang
2022-01-10 10:19:07 +08:00
你说的对,当指针作为返回值,一定发生逃逸。如果是传值进来,则是可能发生逃逸,所以相对来说更 GC 友好一些,但其实这么对比没什么意义。

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

这种写法,只是更不容易发生逃逸,但是但凡你函数内用到任意一个会发生逃逸的函数,你前面的工作就全白费了,比如 `fmt.Printf(b)`,所以实际写的时候不会在这两种写法上纠结,因为没法保证一定不逃逸。
wheeler
2022-01-10 12:09:13 +08:00
看到了官方的 FAQ:

https://go.dev/doc/faq#stack_or_heap
hzzhzzdogee
2022-01-10 13:31:58 +08:00
是的, 第二种不一定发生逃逸.

但是除非有理由, 我个人更推荐第一种写成 func aToB (a* A) B {}
hellloworld
2022-01-10 18:00:50 +08:00
b 原本的值还是会逃逸的吧,进入栈内的是地址,差距不大

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/827176

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX