3

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

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

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

4

6 回答 6

15

首先要做的事:不要显式调用 GC

除非你有一个很好的理由。即使你认为你有,你也可能没有。

GC 知道它在做什么(大多数时候......)

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

GC 并不总是关心你说什么

如果你这样做是有充分理由的,或者你真的想确保以可能的最佳内存状态开始一个密集的代码部分,你需要知道这可能行不通:调用System.gc()不保证如其Javadoc 强调我的)所提到的,将进行垃圾收集:

调用 gc 方法表明Java 虚拟机将努力回收未使用的对象。

其他建议

追捕并杀死(坏)显式 GC

  • 打开-XX:+DisableExplicitGC(如果你的 JVM 支持它)以防止那些疯狂的调用造成任何伤害(在评论中感谢 Fredrik)
  • 使用您最喜欢的 IDE 或grep调用System.gc()及其等价物查找并摆脱它们。

寻找另一种方式

有关其他有用的建议(例如使用s) ,请参阅Grooveek 的回答。WeakReference

尝试其他 GC 并为您的应用微调您的虚拟机

根据您的用例,也许尝试其他 GC 实现可能会有所帮助:CMC、G1、ParallelGC 等... 6 次更新,自 Java 7 发布以来,长期运行密集型企业应用程序。

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

延伸阅读

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

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

于 2011-05-31T20:54:35.390 回答
3

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

于 2011-05-31T20:56:24.973 回答
2

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

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.
于 2011-05-31T21:10:19.680 回答
0

As others have said, calling System.gc() is usually a mistake. (Not always ... )

Assuming that you have one of those rare use-cases where calling System.gc() is likely to be beneficial, there are two cases to consider:

  • If your JVM is using a classical "stop the world" collector, then running it in a separate thread will make no difference. The GC stops all application threads for the duration.

  • If your JVM is running a concurrent collector, then running it in a separate thread may be a good idea. It is true that all collectors have a phase in which all threads are stopped, but calling System.gc() is documented as returning after "the Java Virtual Machine has made a best effort to reclaim space from all discarded objects". So running it in a separate thread will allow the current thread to do something else. However, you need to be careful to avoid launching multiple threads that each call System.gc(); i.e. the code that is responsible for launching the thread needs to keep track of any previous GC threads.

于 2011-05-31T23:37:55.207 回答
0

除了到目前为止已经说过的内容之外,整个想法存在严重缺陷,因为您遗憾地错过了一个重要细节:

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

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

于 2011-05-31T21:14:24.730 回答
0

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

但是,在某些极端情况下您会想要这样做:当内存运行非常短并且应用程序可能会崩溃时。但是很多可以做的是应用程序的设计和实现来避免这些情况。

在回收内存和避免内存泄漏方面,我喜欢的 Java 功能之一是WeakReference对象。他们是你的朋友。

于 2011-05-31T21:16:22.323 回答