我可以在Java中强制进行垃圾回收吗?

11

可能是重复问题:
在Java中强制进行垃圾回收?

我能通过任何手段强制在Java中进行垃圾回收吗?

System.gc()只是一种建议。它是没有用的。

当我确定某些资源不再使用时,为什么不能强制清理它们呢?

就像C ++中的delete()和C中的free()一样?

当有大量无法重复使用的资源时,这确实会影响性能。我们所能做的就是睡觉(sleep())。

有什么解决方案吗?谢谢

3个回答

14
不行,System.gc() 是你能得到的最接近操作了。Java 不同于 C 或 C++,JVM 会为你管理内存,因此你不具备那种细粒度控制。如果你将不再使用的对象设置为 null 或失去所有引用,它们就会被清理。而且 GC 很聪明,所以应该能很好地照顾你。
话虽如此,如果你用的是 Unix 系统,并强制执行线程转储(kill -3),它几乎会强制进行垃圾回收。

5
对“GC很聪明”的赞同。(它确实非常聪明,并且很少是性能瓶颈的真正原因。) - Louis Wasserman
@Michael 关于 Unix 系统和强制线程转储的问题是什么?这如何保证垃圾回收? - Geek
1
@Geek - 每当JVM执行线程转储时,它会暂停自身进行垃圾回收。实际上,它可以在任何操作系统上执行此操作,只是在Unix / Linux上由于“kill”命令的可用性而更容易执行。如果您使用Cygwin在Windows上运行,则可以完成相同的操作。 - Michael

6
如果你的内存不足,那么你应该不要试图强制进行GC - 这意味着你的代码存在内存泄漏。此时强制GC是没有用的,因为如果你仍然持有对象的引用,它仍然不会被垃圾收集器回收。
你需要做的是解决真正的问题,并确保你不再持有不再使用的对象的引用。
一些常见的罪魁祸首包括:
- 在一个大的对象图中持有大量的引用,这些引用永远不会被清除。当你不再需要它们时,请将引用设置为null,或者更好的方法是简化你的对象图,使其不需要所有额外的长期引用。 - 在哈希表或类似的数据结构中缓存对象,导致随着时间的推移变得越来越庞大。停止这样做,或者使用像Google的CacheBuilder这样的软引用缓存。 - 在长时间内对大量不同的字符串上过度使用String.intern()方法。 - 引用比它们需要的范围更大。例如,你是否在使用实例变量时可以使用局部变量?

好的建议。我会尝试一下。谢谢。 - Jacob
2
有时候有强制进行垃圾回收的原因。最明显的是,如果您即将进入与真实世界交互的延迟敏感代码,并希望最小化GC暂停进行“大型”收集的机会。当然,如果延迟非常重要,Java可能不是解决问题的最佳语言,但有时您处于无法撤消这种错误的位置。 - Jon Watte
我刚刚调试了一个应用程序,当内存无法控制地增长,并且很快耗尽了150GB时。在关键位置添加System.gc()解决了这个问题,并将其保持在35GB以下。该应用程序需要大量的内存和高度并行。GC不是万能的,它针对典型的使用情况进行了优化。有时即使所有引用都被释放/超出范围,也有必要给gc()提示。 - morfizm
如果在您的代码中使用了 WeakReference,那么在单元测试中,强制垃圾收集特定对象以检查当对象消失时,您的弱引用逻辑是否正常工作是合理的。 - flodin

1

无法显式指示JVM收集垃圾。只有在系统需要资源时才会执行此操作。

我所知道的唯二可能启动GC的操作如下:

  1. 正如您所说,尝试通过调用System.gc()“建议”现在是一个好时机。
  2. 将您不使用的任何引用设置为null引用,使元素有资格进行收集。

关于我的第二点,请参见此处的答案:Java中的垃圾收集器-将对象设置为空。实质上,如果您不使您不需要的对象可供垃圾收集(通过失去对其的引用),那么垃圾收集器没有运行的理由,因为它不知道任何可用的垃圾。

此外,重要的是考虑为什么/如何内存中的这些对象会影响性能:

  • 你是否遇到了很多OutOfMemoryExceptions?这个问题可以通过第二点和增加JVM可用堆空间来解决。
  • 你是否进行过测量,看看在JVM分配的堆空间中增加更多对象是否会对性能产生影响?确定何时可以更早地释放对象的引用可能有助于减少这些问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接