golang之runtime.SetFinalizer

前端之家收集整理的这篇文章主要介绍了golang之runtime.SetFinalizer前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

在实际的编程中,我们都希望每个对象释放时执行一个方法,在该方法内执行一些计数、释放或特定的要求,以往都是在对象指针置nil前调用一个特定的方法,golang提供了runtime.SetFinalizer函数,当GC准备释放对象时,会回调该函数指定的方法,非常方便和有效。

不过值得注意的是,指针构成的 "循环引⽤" 加上 runtime.SetFinalizer 会导致内存泄露。

  1. type Data struct {
  2. d [1024 * 100]byte
  3. o *Data
  4. }
  5. func test() {
  6. var a,b Data
  7. a.o = &b
  8. b.o = &a
  9. runtime.SetFinalizer(&a,func(d *Data) { fmt.Printf("a %p final.\n",d) })
  10. runtime.SetFinalizer(&b,func(d *Data) { fmt.Printf("b %p final.\n",d) })
  11. }
  12. func main() {
  13. for {
  14. test()
  15. time.Sleep(time.Millisecond)
  16. }
  17. }

输出

  1. $ go build -gcflags "-N -l" && GODEBUG="gctrace=1" ./test
  2. gc11(1): 2+0+0 ms,104 -> 104 MB 1127 -> 1127 (1180-53) objects
  3. gc12(1): 4+0+0 ms,208 -> 208 MB 2151 -> 2151 (2226-75) objects
  4. gc13(1): 8+0+1 ms,416 -> 416 MB 4198 -> 4198 (4307-109) objects

垃圾回收器能正确处理 "指针循环引⽤",但⽆法确定 Finalizer 依赖次序,也就⽆法调⽤ Finalizer 函数,这会导致目标对象⽆法变成不可达状态,其所占⽤内存⽆法被回收。

猜你在找的Go相关文章