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

lcm*_*lin 8 garbage-collection memory-leaks automatic-ref-counting

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

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

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

Cat*_*Man 22

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

GC专业人士:

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

ARC职业选手:

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

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

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

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