运行时GC比编译时ARC有什么优势?

时间:2015-09-09 04:16:10

标签: memory-leaks garbage-collection automatic-ref-counting

一些较新的语言正在将ARC应用到他们的编译器中(Swift和Rust,仅举几例)。据我所知,这实现了与运行时GC相同的功能(将手动解除分配的负担远离程序员),同时显着提高效率。

我知道ARC可能会成为一个复杂的过程,但由于现代垃圾收集器的复杂性,实现ARC似乎并不复杂。但是,仍有大量的语言和框架使用GC进行内存管理,甚至用于系统编程的Go语言也使用GC。

我真的不明白为什么GC会优于ARC。我在这里错过了什么吗?

1 个答案:

答案 0 :(得分:22)

这里涉及一系列权衡,这是一个复杂的话题。这是最重要的:

GC专业人士:

  • 跟踪垃圾收集器可以处理对象图中的循环。自动引用计数将泄漏内存,除非通过删除引用或确定图形的哪个边缘应该弱而手动中断周期。这在引用计数应用程序的实践中是一个非常常见的问题。
  • 跟踪垃圾收集器实际上可以比引用计数更快(在吞吐量方面),通过同时进行工作,通过批处理工作,延迟工作,以及不会弄乱缓存热循环中的引用计数的缓存。
  • 复制收集器可以压缩堆,回收碎片页面以减少占用空间

ARC专业人士:

  • 因为当引用计数达到0时会立即发生对象破坏,所以可以使用对象生存期来管理非内存资源。使用垃圾收集,生命周期是不确定的,因此这不安全。
  • 收集工作通常更加分散,导致暂停时间更短(如果您释放一个大的对象子图,仍然可以暂停)
  • 因为内存是同步收集的,所以不可能通过分配比清理它更快的速度“超越收集器”。当虚拟机分页发挥作用时,这一点尤其重要,因为有一些退化的情况,即GC线程点击了一个被分页的页面,并且远远落后。
  • 在相关的说明中,跟踪垃圾收集器必须遍历整个对象图,这会强制进行不必要的页面调整(对此有缓解,如https://people.cs.umass.edu/~emery/pubs/f034-hertz.pdf,但它们没有被广泛部署)
  • 跟踪垃圾收集器通常需要比引用计数更多的“临时空间”,如果他们想要达到其全部吞吐量

我个人对此的看法是,对于大多数情况,真正重要的唯一两点是:

  • ARC不收集周期
  • GC没有确定性的生命周期

我觉得这两个问题都是交易破坏者,但是如果没有更好的想法,你只需挑选哪个可怕的问题听起来更糟糕。