前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >什么是 Go runtime.KeepAlive?

什么是 Go runtime.KeepAlive?

作者头像
haohongfan
发布2021-12-02 12:28:52
1.5K0
发布2021-12-02 12:28:52
举报
文章被收录于专栏:HHFCodeRvHHFCodeRv

有些同学喜欢利用 runtime.SetFinalizer 模拟析构函数,当变量被回收时,执行一些回收操作,加速一些资源的释放。在做性能优化的时候这样做确实有一定的效果,不过这样做是有一定的风险的。

比如下面这段代码,初始化一个文件描述符,当 GC 发生时释放掉无效的文件描述符。

代码语言:javascript
复制

type File struct { d int }

func main() {
    p := openFile("t.txt")
    content := readFile(p.d)

    println("Here is the content: "+content)
}

func openFile(path string) *File {
    d, err := syscall.Open(path, syscall.O_RDONLY, 0)
    if err != nil {
      panic(err)
    }

    p := &File{d}
    runtime.SetFinalizer(p, func(p *File) {
      syscall.Close(p.d)
    })

    return p
}

func readFile(descriptor int) string {
    doSomeAllocation()

    var buf [1000]byte
    _, err := syscall.Read(descriptor, buf[:])
    if err != nil {
      panic(err)
    }

    return string(buf[:])
}

func doSomeAllocation() {
    var a *int

    // memory increase to force the GC
    for i:= 0; i < 10000000; i++ {
      i := 1
      a = &i
    }

    _ = a
}

上面这段代码是对 go 官方文档[1]的一个延伸,doSomeAllocation 会强制执行 GC,当我们执行这段代码时会出现下面的错误。

代码语言:javascript
复制
panic: no such file or directory

goroutine 1 [running]:
main.openFile(0x107a65e, 0x5, 0x10d9220)
        main.go:20 +0xe5
main.main()
        main.go:11 +0x3a

这是因为 syscall.Open 产生的文件描述符比较特殊,是个 int 类型,当以值拷贝的方式在函数间传递时,并不会让 File.d 产生引用关系,于是 GC 发生时就会调用 runtime.SetFinalizer(p, func(p *File) 导致文件描述符被 close 掉。

什么是 runtime.KeepAlive ?

如上面的例子,我们如果才能让文件描述符不被 gc 给释放掉呢?其实很简单,只需要调用 runtime.KeepAlive 即可。

代码语言:javascript
复制
func main() {
    p := openFile("t.txt")
    content := readFile(p.d)
    
    runtime.KeepAlive(p)

    println("Here is the content: "+content)
}

runtime.KeepAlive 能阻止 runtime.SetFinalizer 延迟发生,保证我们的变量不被 GC 所回收。

结论

正常情况下,runtime.KeepAlive,runtime.SetFinalizer 不应该被滥用,当我们真的需要使用时候,要注意使用是否合理。

《性能优化 | Go Ballast 让内存控制更加丝滑》我们说到如何让整个程序的声明周期内维护一个 slice 不被 gc 给回收掉,这里就用到了 runtime.KeepAlive。

这里还有有一篇关于 runtime.KeepAlive 的文档[2],有兴趣的可以看一下。

参考资料

[1]go 官方文档: https://pkg.go.dev/runtime#KeepAlive

[2]文档: https://medium.com/a-journey-with-go/go-keeping-a-variable-alive-c28e3633673a

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-11-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 HHFCodeRv 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是 runtime.KeepAlive ?
  • 结论
    • 参考资料
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档