自己碰到一个情况, 就是 for 循环中, 每个循环中都创建了变量, 但是因为实际内存不受 GC 管理. 需要手动的进行释放. Gemini 提供了一个方式, 是通过匿名函数 + defer 进行释放
for _, item := range list {
func(){
src := new NoGCSource{item}
defer src.Close()
}()
}
这种方式是 go 中处理这类情况, 比较优秀的方式吗. 有什么需要注意和思考的地方吗.
1
iOCZS 12 小时 52 分钟前 ![]() 抛开语言而言,还是要看你要持有多久。defer 本质只是一个作用域内的释放。有些东西你想持有得更久。
|
![]() |
2
maocat 12 小时 50 分钟前 via Android ![]() sync.pool
|
![]() |
3
BenHunDun OP @iOCZS #1 就是只有单个循环里处理和使用这个变量, 也不影响到下个循环. 变量也不返回给其他地方.
这个方式是 Gemini 推荐的. 自己细看下来以及向 Gemini 后续提问都没有发现什么问题. 但第一次看到这中处理方式, 还是不确定是不是一种 "好/常用" 的方式 |
![]() |
4
bv 12 小时 24 分钟前 ![]() defer 是函数级的,每一个 defer 都会向函数栈上记录一个调用信息,在 for 循环里面用 defer 这会占用大量栈空间,可能导致内存压力甚至栈溢出。使用闭包函数算是将 defer 的作用域细分隔离至一个小的函数作用域内。闭包函数执行完,defer 就会立即执行。
|
5
cryptovae 12 小时 23 分钟前
必然不是一种好方式,这块肯定是要把代码拆分出来作为一个单独的函数,函数自己内部控制变量的 close 状态,你这种 Gemini 告诉你的形式更像是流水账,能用,但是不优雅
|
![]() |
6
bv 12 小时 21 分钟前
对此我一般都是将 for 内的函数拆分成单独的函数,例如:
for _, item := range list { foo(item) } func foo(item T) { src :=NoGCSource(item) defer src.Close() // TODO 业务逻辑 } |
![]() |
7
dacapoday 12 小时 10 分钟前 ![]() 什么 go 版本,官方不是出了 AddCleanup 来管理这种 非 golang runtime 分配的资源?
https://pkg.go.dev/runtime#AddCleanup 而且既然 item 所引用的资源的生命周期仅在一次循环迭代范围内,为什么不在循环体 外声明 item ,在循环体内末尾默认添加 Close 。如果怕循环体内 panic ,也可以在 item 声明时,添加 defer ,检测 panic 发生,并释放此时 item 引用的资源。 或者 item 的生命周期都归 list 管,循环结束后,由 list 统一释放。 |
![]() |
8
lysShub 7 小时 19 分钟前
如果不是高频调用的地方,包一个函数,把 c 内存复制到 go 内存中
|
![]() |
9
BenHunDun OP |
![]() |
10
BenHunDun OP @dacapoday 自己的环境是 1.24 的版本. 但简单的询问 ChatGPT 说 addCleanup 不适合这个场景. 会自身再确认下 AddCeanup 的作用.
很感谢, 了解到了新的东西. > 如果怕循环体内 panic ,也可以在 item 声明时,添加 defer ,检测 panic 发生,并释放此时 item 引用的资源。 这部分就是看到用函数的方式缩小了 item 资源的作用域, 感觉上内存会更快的被释放. 然后看到提供了这种方式, 看起来好像不会产生一些新的问题, 但是没碰到该写法, 所以想像 v 站的大佬们问下可行的方式. 或者其他更加优秀的处理方式. |