智能垃圾收集?

时间:2011-05-31 20:53:19

标签: java garbage-collection stability

您可以通过调用System.gc()简单地在Java中进行垃圾收集,但有时这会“拖延”应用程序。这样的垃圾收集是一个坏主意,并避免失速:

new Thread(new Runnable() {
   public void run() { 
      System.gc(); 
   }
}).start();

或者这可能导致更多问题?

6 个答案:

答案 0 :(得分:15)

首先要做的事情: 不要明白地呼叫GC

除非你有充分的理由。即使你认为你这样做,你可能也不会。

GC知道它正在做什么 (大部分时间......)

如果你继续阅读,我假设你有一个非常好的(虽然可能是扭曲的)理由试图搞砸GC,尽管它很可能比你在确定什么时候更聪明它应该收集记忆。另外,请记住,通过明确地调用它,你会混淆它并搞砸它的启发式,所以它变得不像以前那么聪明。所有这些都是因为你试图超越它。

GC并不总是关心你所说的

如果你出于一个很好的理由这样做,或者你真的想确保你启动一个具有最佳内存状态的密集代码部分,你需要知道这可能不起作用:调用System.gc()不保证会发生垃圾回收,如上所述by its Javadoc 强调我的

  

调用gc方法建议 Java虚拟机花费精力   回收未使用的物品。

其他建议

追捕并杀死(坏)显式GC

  • 打开-XX:+DisableExplicitGC(如果您的JVM支持它)以防止那些疯狂的呼叫造成任何伤害(在评论中归功于Fredrik)
  • 使用您最喜欢的IDE或grep查看对System.gc()及其等效内容的调用,然后将其删除。

寻找另一种方式

请参阅Grooveek's answer了解其他有用的建议(例如使用WeakReference)。

使用其他GC进行实验并为您的应用程序微调VM

根据您的使用案例,可能尝试其他GC实施可能会有所帮助:CMC,G1,ParallelGC等...如果您想避免“失速”,我在G1中引入了非常好的结果最新的Java SE 6更新以及自Java 7发布以来,在长时间运行的情况下运行密集型企业应用程序。

请注意,JVM调优是一项非常复杂的艺术。

进一步阅读

您可以浏览这些内容以获取更多详细信息:

* 谨慎使用:有时不完全是最新的,不记录所有内容,并列出了许多实验性功能或仅限HotSpot的功能。

答案 1 :(得分:3)

是的,大多数情况下调用System.gc()是一个非常糟糕的主意。有一些例外,但它们很少,最好花时间确保你没有在GC环境中做出损害性能的事情,并且研究并确保你理解gc如何工作而不是试图自己处理它显式调用System.gc()。

答案 2 :(得分:2)

我无法击败@haylem回答的清晰度和力量,对不起。但是,我要补充说,有很多(更好的)方法来管理Java中的内存。例如,有WeakReference和处理这些的集合,如WeakHashMap。这些是确定性处理内存的方法,尽管对于GC的显式调用不是,根据javadoc

Calling the gc method suggests that the Java Virtual Machine expend effort toward 
recycling unused objects in order to make the memory they currently occupy available 
for quick reuse. When control returns from the method call, the Java Virtual Machine 
has made a best effort to reclaim space from all discarded objects.

答案 3 :(得分:0)

除了到目前为止已经说过的话,整个想法都有可怕的缺陷,因为你遗憾地错过了一个重要的细节:

当一个完整的GC正在运行时,应用程序将被停止!(至少目前在一个现代的Hotspot VM上 - 你还会使用什么?)

有一个并发标记&在热点中扫描实现(虽然afaik默认情况下未激活),但是这会产生一些额外的开销,并且仍然必须在执行扫描之前停止所有线程。因此,基本上不重要的是你从哪个线程System.gc()VM将等待所有线程到达安全点,停止它们然后进行收集。所以使用线程是完全没用的。

答案 4 :(得分:0)

我完全同意一般不建议明确地调用垃圾收集器。它可以使应用程序停顿几秒钟,有时甚至几分钟。如果您正在处理后台服务,这通常不是问题,但如果它暴露给用户,他们将会有糟糕的体验。

但是,在极端情况下,您需要执行此操作:内存运行时间非常短且应用程序可能崩溃。但是,可以做的很多是应用程序的设计和实现,以避免这些情况。

在回忆内存和避免内存泄漏方面,我喜欢Java的一个特性是WeakReference个对象。他们是你的朋友。

答案 5 :(得分:0)

正如其他人所说,调用System.gc()通常是一个错误。 (不总是 ...)

假设你有一个罕见的用例,其中调用System.gc()可能是有益的,有两种情况需要考虑:

  • 如果您的JVM使用经典的“停止世界”收集器,那么在单独的线程中运行它将没有任何区别。 GC会在一段时间内停止所有应用程序线程。

  • 如果您的JVM正在运行并发收集器,那么在单独的线程中运行它可能是个好主意。确实,所有收集器都有一个停止所有线程的阶段,但调用System.gc()被记录为在之后返回“Java虚拟机已尽最大努力从所有丢弃的对象中回收空间”< / em>的。因此,在单独的线程中运行它将允许当前线程执行其他操作。但是,您需要小心避免启动多个线程,每个线程调用System.gc();即,负责启动线程的代码需要跟踪任何以前的GC线程。