使用垃圾收集有什么缺点?

时间:2010-07-09 17:13:57

标签: garbage-collection

大多数现代语言都内置垃圾收集(GC)。例如Java,.NET语言,Ruby等。事实上,GC以多种方式简化了应用程序开发。

我很想知道用GCed语言编写应用程序的限制/缺点。假设GC实施是最佳的,我只是想知道GC可能会限制我们做出一些优化决策。

8 个答案:

答案 0 :(得分:23)

在我看来,使用垃圾收集器的主要缺点是:

  1. 资源的非确定性清理。有时,说“我已经完成了这个,我现在想要它清理”是很方便的。使用GC,这通常意味着强制GC清理所有内容,或者等到它准备就绪 - 这两者都会剥夺您作为开发人员的控制权。

  2. GC的非确定性操作引起的潜在性能问题。当GC收集时,通常会看到(小)挂起等。对于诸如实时模拟或游戏之类的事情,这可能特别成问题。

答案 1 :(得分:12)

从C程序员那里拿走......这是关于成本/收益和适当使用

诸如三色/标记和扫描之类的垃圾收集算法通常在“丢失”的资源和被释放的物理资源之间存在显着的延迟。在某些运行时,GC实际上会暂停执行程序以执行垃圾收集。

作为一名长期的C程序员,我可以告诉你:

a)手动free()垃圾收集很难 - 这是因为人类放置free()调用的错误率通常高于GC算法。

b)手动free()垃圾收集成本时间 - 调试时间是否超过GC的毫秒暂停?如果你正在编写游戏而不是嵌入式内核,那么使用垃圾收集可能是有益的。

但是,当您无法承受运行时缺点(正确的资源,实时约束)时,执行手动资源分配可能会更好。这可能需要一段时间,但可以100%有效。

试着想象用Java编写的操作系统内核?或者在带有GC的.NET运行时...只需看看JVM在运行简单程序时累积了多少内存。我知道项目存在这样......他们只是让我觉得有点不舒服。

请记住,我的linux机箱今天使用3GB内存的功能与多年前的512MB RAM相同。唯一的区别是我有mono / jvm / firefox等运行。 GC的商业案例很明确,但它仍然让我感到很不舒服。

好书:

Dragon book (recent edition)Modern Compiler Implementation in C

答案 2 :(得分:6)

对于.NET,我可以看到两个缺点。

1)人们认为GC最了解,但情况并非总是如此。如果您进行某些类型的分配,您可以让自己在没有直接调用GC的情况下体验一些非常讨厌的程序死亡。

2)大于85k的物体进入LOH或大物体堆。该堆当前从未被压缩,因此,当LOH实际上没有足够的压缩以供您进行另一次分配时,您的程序可能会遇到内存不足异常。

我在这个问题中发布的代码中显示了这两个错误:

How do I get .NET to garbage collect aggressively?

答案 3 :(得分:4)

  

我很想知道用GCed语言编写应用程序的限制/缺点。假设GC实施是最佳的,我只是想知道GC可能会限制我们做出一些优化决策。

我的信念是,自动记忆管理对效率施加了限制,但我没有证据证明这一点。特别是,今天的GC算法只提供高吞吐量或低延迟,但不能同时提供。像.NET和HotSpot JVM这样的生产系统正因为它们针对吞吐量进行了优化而产生了显着的暂停。像Staccato这样的专业GC算法提供了更低的延迟,但代价是降低了最小的mutator利用率,因此吞吐量很低。

答案 4 :(得分:2)

如果你对自己的记忆管理技巧充满信心,那就没有优势了。

该概念的引入是为了最大限度地缩短开发时间,并且由于缺乏完全理解记忆的编程专家。

答案 5 :(得分:1)

性能(尤其是实时系统)的最大问题是,当GC启动时,您的程序可能会遇到一些意外延迟。但是,现代GC尝试避免这种情况并且可以实时调整目的。

另一个显而易见的事情是你无法自己管理内存(例如,在numa本地内存上分配),在实现低级软件时可能需要这样做。

答案 6 :(得分:1)

几乎不可能使非GC内存管理器在多CPU环境中工作,而不需要在每次分配或释放内存时获取和释放锁。每次锁定获取或释放都需要CPU来协调其与其他CPU的操作,并且这种协调往往相当昂贵。基于垃圾收集的系统可以允许进行许多内存分配,而无需任何锁定或其他CPU间协调。这是一个主要优势。缺点是垃圾收集中的许多步骤要求CPU协调其操作,并且获得良好的性能通常要求将这些步骤合并到很大程度(如果消除了对每个内存分配的CPU协调要求,那么没有多大好处CPU必须在垃圾收集的每个步骤之前进行协调)。这种合并通常会导致系统中的所有任务在收集期间暂停不同的时间;一般来说,人们愿意接受的停顿时间越长,收集所需的总时间就越少。

如果处理器要返回基于描述符的句柄/指针系统(类似于80286所使用的,虽然现在不再使用16位段),垃圾收集可以同时完成与其他操作(如果GC想要移动它时使用句柄,使用句柄的任务必须在数据从其旧地址复制到新地址时冻结,但这不应该花费很长时间) 。不确定是否会发生这种情况(顺便提一下,如果我有我的druthers,对象引用将是32位,指针将是一个对象引用加上一个32位偏移;我认为它将是一段时间之前有一个需要超过20亿个对象,或超过4个演出的任何对象。尽管摩尔定律,如果一个应用程序有超过20亿个对象,它的性能可能会通过使用更少,更大的对象来改善。如果应用程序需要一个对象超过4场演出,使用更多更小的物体可能会提高其性能。)

答案 7 :(得分:0)

通常,垃圾收集有一些缺点:

  • 垃圾收集消耗计算资源来决定释放哪些内存,重建程序员可能已知的事实。为了方便在源代码中手动注释对象生存期而造成的损失是开销,通常会导致性能下降或不均匀。与内存层次结构效应的交互可能会使这种开销在难以预测或在常规测试中检测到的情况下无法忍受。
  • 实际收集垃圾的时间点可能无法预测,导致在整个会话期间分散的停顿。在设备驱动程序,事务处理或交互式程序等实时环境中,不可预测的停顿是不可接受的。
  • 尽管存在垃圾收集器,但如果对未使用的对象的引用本身并未手动处理,则内存可能会泄漏。这被描述为逻辑内存泄漏。[3]例如,递归算法通常会延迟堆栈对象的释放,直到最终调用完成为止。缓存和记忆,常见的优化技术,通常会导致这种逻辑泄漏。垃圾收集消除所有泄漏的信念导致许多程序员不要防止造成这种泄漏。
  • 在现代台式计算机典型的虚拟内存环境中,垃圾收集器很难注意到何时需要收集,导致大量累积垃圾,长时间的破坏性收集阶段以及其他程序的数据被换出
  • 也许最重要的问题是依赖垃圾收集器的程序通常表现出较差的位置(与缓存和虚拟内存系统交互不良),占用的地址空间比程序实际上在任何时候实际使用的地址空间多,并触摸其他空闲页面。这些可能结合在一种称为颠簸的现象中,其中程序花费更多时间在不同级别的存储之间复制数据而不是执行有用的工作。它们可能使程序员无法推断设计选择的性能影响,使性能调整变得困难。它们可能导致垃圾收集程序干扰其他竞争资源的程序