为什么永远不会调用终结器?
Why finalizer is never called?
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)
}
上面的代码试图通过 SetFinalizer
重用对象,但调试后我发现终结器从未被调用,为什么?
更新
The above code tries to reuse object by SetFinalizer
, but after debug I found finalizer is never called, why?
finalizer 仅在 GC 时在对象上调用
将其标记为未使用,然后尝试在最后清扫(免费)
GC 周期。
作为推论,如果在程序的 运行 时间内从未执行 GC 循环,则可能永远不会调用您设置的终结器。
以防万一您可能对 Go 的 GC 持有错误的假设,可能值得注意的是 Go 不对值使用引用计数;相反,它使用与程序并行工作的 GC,并且它工作的会话定期发生,并由某些参数触发,例如分配产生的堆压力。
一些关于终结器的注释:
程序终止时,不强制GC运行.
由此推论,无法保证终结器
完全 运行。
如果 GC 在即将释放的对象上找到终结器,
它调用终结器 但不释放对象。
对象本身只会在下一个 GC 周期被释放 —
浪费内存。
总而言之,您似乎在尝试实现析构函数。
请不要:让您的对象实现称为 Close
的那种标准方法,并在您的类型的合同中声明程序员在完成该对象后必须调用它。
当程序员无论如何都想调用这样的方法时,他们使用 defer
.
请注意,此方法适用于 Go 中的所有类型
stdlib 包装由 OS 提供的资源——文件和套接字描述符。所以没有必要假装你的类型有什么不同。
另一个需要记住的有用的事情是,Go 被明确设计为严肃、简洁、没有魔法、 面对面的语言,并且你只是想给它添加魔法。
请不要,那些喜欢解密魔法层的人会使用 Scala 不同的语言进行编程。
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)
}
上面的代码试图通过 SetFinalizer
重用对象,但调试后我发现终结器从未被调用,为什么?
更新
The above code tries to reuse object by
SetFinalizer
, but after debug I found finalizer is never called, why?
finalizer 仅在 GC 时在对象上调用 将其标记为未使用,然后尝试在最后清扫(免费) GC 周期。
作为推论,如果在程序的 运行 时间内从未执行 GC 循环,则可能永远不会调用您设置的终结器。
以防万一您可能对 Go 的 GC 持有错误的假设,可能值得注意的是 Go 不对值使用引用计数;相反,它使用与程序并行工作的 GC,并且它工作的会话定期发生,并由某些参数触发,例如分配产生的堆压力。
一些关于终结器的注释:
程序终止时,不强制GC运行.
由此推论,无法保证终结器 完全 运行。
如果 GC 在即将释放的对象上找到终结器, 它调用终结器 但不释放对象。
对象本身只会在下一个 GC 周期被释放 — 浪费内存。
总而言之,您似乎在尝试实现析构函数。
请不要:让您的对象实现称为 Close
的那种标准方法,并在您的类型的合同中声明程序员在完成该对象后必须调用它。
当程序员无论如何都想调用这样的方法时,他们使用 defer
.
请注意,此方法适用于 Go 中的所有类型 stdlib 包装由 OS 提供的资源——文件和套接字描述符。所以没有必要假装你的类型有什么不同。
另一个需要记住的有用的事情是,Go 被明确设计为严肃、简洁、没有魔法、 面对面的语言,并且你只是想给它添加魔法。
请不要,那些喜欢解密魔法层的人会使用 Scala 不同的语言进行编程。