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不同的语言进行编程。
- 1 回答
- 0 关注
- 119 浏览
添加回答
举报
0/150
提交
取消