为了账号安全,请及时绑定邮箱和手机立即绑定

为什么永远不会调用终结器?

为什么永远不会调用终结器?

Go
泛舟湖上清波郎朗 2023-04-24 16:50:59
var p = &sync.Pool{    New: func() interface{} {        return &serveconn{}    },}func newServeConn() *serveconn {    sc := p.Get().(*serveconn)    runtime.SetFinalizer(sc, (*serveconn).finalize)    fmt.Println(sc, "SetFinalizer")    return sc}func (sc *serveconn) finalize() {    fmt.Println(sc, "finalize")    *sc = serveconn{}    runtime.SetFinalizer(sc, nil)    p.Put(sc)}上面的代码尝试重用 object by SetFinalizer,但调试后我发现 finalizer 从未被调用,为什么?更新这可能是相关的: https: //github.com/golang/go/issues/2368
查看完整描述

1 回答

?
繁星coding

TA贡献1797条经验 获得超4个赞

上面的代码尝试重用 object by SetFinalizer,但调试后我发现 finalizer 从未被调用,为什么?

仅当 GC 将对象标记为未使用时才会调用终结器,然后在 GC 周期结束时尝试清扫(释放)。

作为必然结果,如果在程序运行期间从未执行 GC 循环,则可能永远不会调用您设置的终结器。

以防万一您可能对 Go 的 GC 持有错误的假设,可能值得注意的是 Go 不对值使用引用计数;相反,它使用与程序并行工作的 GC,并且它工作的会话定期发生,并由某些参数触发,例如分配产生的堆压力。

关于终结器的一些注释:

  • 当程序终止时,不会强制运行 GC。

    这样做的一个必然结果是终结器根本不能保证运行。

  • 如果 GC 在将要释放的对象上找到终结器,它会调用终结器但不会释放该对象。

    对象本身只会在下一个 GC 周期被释放——浪费内存。

总而言之,您看起来像是在尝试实现析构函数。请不要:让你的对象实现被调用的那种标准方法,Close并在你的类型的契约中声明程序员在完成对象时需要调用它。当程序员无论如何都想调用这样的方法时,他们会使用defer.

请注意,这种方法非常适用于 Go stdlib 中的所有类型,这些类型包装了操作系统提供的资源——文件和套接字描述符。所以没有必要假装你的类型有什么不同。

要记住的另一件有用的事情是,Go 被明确设计为严肃、简洁、没有魔法、面对面的语言,而您只是想为其添加魔法。请不要,那些喜欢解密魔法层的人会使用Scala不同的语言进行编程。


查看完整回答
反对 回复 2023-04-24
  • 1 回答
  • 0 关注
  • 119 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信