Go 性能优化技巧 10/10

作者: qyuhen | 来源:发表于2016-05-05 10:00 被阅读559次

垃圾回收不是万能的,Go 一样存在资源泄露问题。

1 SetFinalizer

虽然垃圾回收器能很好地处理循环引用,可一旦加上 SetFinalizer,事情就不那么美妙了。

显然,这些对象并未被释放。在标准库文档里有这样的描述:

Finalizers are run in dependency order: if A points at B, both have finalizers, and they are otherwise unreachable, only the finalizer for A runs; once A is freed, the finalizer for B can run. If a cyclic structure includes a block with a finalizer, that cycle is not guaranteed to be garbage collected and the finalizer is not guaranteed to run, because there is no ordering that respects the dependencies.

好在这类状况并不常见,SetFinalizer 最大的问题是延长了对象生命周期。在第一次回收时执行 Finalizer 函数,且目标对象重新变成可达状态,直到第二次才真正 “销毁”。这对于有大量对象分配的高并发算法,可能会造成很大麻烦。

SetFinalizer sets the finalizer associated with x to f. When the garbage collector finds an unreachable block with an associated finalizer, it clears the association and runs f(x) in a separate goroutine. This makes x reachable again, but now without an associated finalizer. Assuming that SetFinalizer is not called again, the next time the garbage collector sees that x is unreachable, it will free x.

2 Goroutine Leak

无论是同步通道(channel),还是带缓冲区的异步通道。当条件不满足时,都会进入等待队列休眠,直到被另一方唤醒。可如果没有被唤醒,那么会出什么问题?

这是个极简单的演示,我们注释掉数据读取方,让发送方全部进入休眠等待状态。按理说,当 test 执行结束后,通道 c 已超出作用域,理应被释放回收,但实际情况是:

这些处于 “chan send” 状态的 G 对象(goroutine)会一直存在,直到唤醒或进程结束,这就是所谓的 “Goroutine Leak”。解决方法很简单,可设置 timeout。或定期用 runtime.Stack 扫描所有 goroutine 调用栈,如果发现某个 goroutine 长时间(阈值)处于 “chan send” 状态,可用一个类似 “/dev/null hole” 的接收器负责唤醒并 “处理” 掉相关数据。

任何机制都有覆盖不到的地方,这就要求我们对底层的某些实现方式有所了解,同时进行严格测试。


本系列结束

下个选题未定,可能会发一些零散技巧过渡。


请关注微信公众号

相关文章

  • Go 性能优化技巧 10/10

    垃圾回收不是万能的,Go 一样存在资源泄露问题。 1SetFinalizer 虽然垃圾回收器能很好地处理循环引用,...

  • Go 性能优化技巧 2/10

    对于一些初学者,自知道 Go 里面的 array 以 pass-by-value 方式传递后,就莫名地引起 “恐慌...

  • Go 性能优化技巧 3/10

    内置 map 类型是必须的。首先,该类型使用频率很高;其次,可借助 runtime 实现深层次优化(比如说字符串转...

  • Go 性能优化技巧 4/10

    延迟调用(defer)确实是一种 “优雅” 机制。可简化代码,并确保即便发生 panic 依然会被执行。如将 pa...

  • Go 性能优化技巧 9/10

    作为内置类型,通道(channel)从运行时得到很多支持,其自身设计也算得上精巧。但不管怎么说,它本质上依旧是一种...

  • Go性能优化技巧 1/10

    字符串(string)作为一种不可变类型,在与字节数组(slice, [ ]byte)转换时需付出 “沉重” 代价...

  • Go 性能优化技巧 8/10

    尽管反射(reflect)存在性能问题,但依然被频繁使用,以弥补静态语言在动态行为上的不足。只是某些时候,我们须对...

  • Go 性能优化技巧 7/10

    接口的用途无需多言。但这并不意味着可在任何场合使用接口,要知道通过接口调用和普通调用存在很大差别。首先,相比静态绑...

  • Go 性能优化技巧 5/10

    闭包(closure)也是很常见的编码模式,因它隐式携带上下文环境变量,因此可让算法代码变得更加简洁。 但任何 “...

  • Go 性能优化技巧 6/10

    Go 使用 channel 实现 CSP 模型。处理双方仅关注通道和数据本身,无需理会对方身份和数量,以此实现结构...

网友评论

    本文标题:Go 性能优化技巧 10/10

    本文链接:https://www.haomeiwen.com/subject/lrrdrttx.html