我有一个在大型数据集上运行的复杂 Java 应用程序。该应用程序执行得相当快,但随着时间的推移,它似乎会消耗大量内存并减慢速度。有没有办法在不重新启动应用程序的情况下运行 JVM 垃圾收集器?
8 回答
不,你不能强制垃圾收集。
即使使用
System.gc();
您可以只请求垃圾收集,但这取决于 JVM 是否这样做。
此外,垃圾收集器足够聪明,可以在需要时收集未使用的内存,因此您应该检查是否以错误的方式处理对象,而不是强制垃圾收集。
如果您以错误的方式处理对象(例如保持对不必要对象的引用),那么 JVM 几乎无法做任何事情来释放内存。
来自文档
调用 gc 方法表明Java 虚拟机花费精力回收未使用的对象,以便使它们当前占用的内存可用于快速重用。当控制从方法调用返回时,Java 虚拟机已尽最大努力 从所有丢弃的对象中回收空间。
打开有关文档 的错误System.gc()
System.gc() 的文档具有极大的误导性,并且没有提及从不调用 System.gc() 的推荐做法。
语言的选择使我们不清楚调用 System.gc() 时的行为是什么,以及哪些外部因素会影响行为。
当您认为应该强制 JVM 释放一些内存时,很少有有用的链接可供访问
1.垃圾收集如何工作
2. System.gc() 什么时候做任何事情
3.为什么调用 System.gc() 是不好的做法?
都说
1. 你无法控制 Java 中的 GC,甚至System.gc()
不保证它。
2. 强迫它的不良做法也可能对性能产生不利影响。
3. 重新审视你的设计,让 JVM 做他的工作 :)
你不应该继续System.gc()
- 如果你觉得你需要强制 GC 运行它通常意味着你的代码/设计有问题。如果您准备好创建未使用的对象,GC 将运行并清除它们 - 请验证您的设计并更多地考虑内存管理,以及查看对象引用中的循环。
这
System.gc()
在java中调用,建议vm运行垃圾收集。虽然它不能保证它会真正做到这一点。尽管如此,您拥有的最佳解决方案。正如其他回复中提到的,jvisualvm 实用程序(自 JDK 6 更新 7 起出现在 JDK 中)也提供了垃圾功能。
编辑:
你的问题让我对这个话题产生了兴趣,我发现了这个资源:
该应用程序执行得相当快,但随着时间的推移,它似乎会消耗大量内存并减慢速度。
这些是 Java 内存的典型症状。很可能在您的应用程序的某个地方有一个不断增长的数据结构。随着堆接近满,JVM 花费越来越多的时间来运行 GC(徒劳)试图收回一些空间。
强制 GC 不会解决这个问题,因为 GC无法收集数据结构。事实上,强制 GC 运行只会让应用程序变慢。
解决问题的方法是找出导致内存泄漏的原因,并修复它。
性能增益/下降取决于您需要垃圾收集的频率、您的 jvm 有多少内存以及您的程序需要多少。
当您调用 System.gc() 时,垃圾收集没有确定性(它只是对解释器的提示),但至少有概率。通过足够数量的调用,您可以仅为您的系统设置实现一些统计上派生的性能乘数。
下图显示了一个示例程序的执行消耗,jvm 分别只为每个试验提供了 1GB(no gc)、1GB(gc)、3GB(gc)、3GB(no gc) 堆。
起初,当 jvm 只分配 1GB 内存而程序需要 3.75GB 时,生产者线程池需要 50 多秒才能完成工作,因为垃圾管理较少导致对象创建率低下。
第二个示例大约快 %40,因为在每次生成 150MB 对象数据之间调用 System.gc()。
在第三个示例中,jvm 在保持 System.gc() 开启的同时获得 3GB 内存空间。正如预期的那样,更多的内存提供了更多的性能。
但是当我在相同的 3GB 环境中关闭 System.gc() 时,它更快!
即使我们不能强制它,如果我们尝试足够长的时间,我们可以在尝试 System.g() 时获得一定百分比的性能提升或消耗。至少在我的带有最新 jvm 的 windows-7 64 位操作系统上。
垃圾收集器自动运行。您不能强制垃圾收集器。
我不建议您这样做,但要强制垃圾收集器从您的 java 代码中运行,您可以使用所有可用内存,这是因为垃圾收集器将在 JVM 抛出 OutOfMemoryError 之前运行...
try {
List<Object> tempList = new ArrayList<Object>();
while (true) {
tempList.add(new byte[Integer.MAX_VALUE]);
}
} catch (OutOfMemoryError OME) {
// OK, Garbage Collector will have run now...
}
我的回答会与其他人不同,但会导致同一点。说明:是的,可以同时使用两种方法强制垃圾收集器以相同的顺序使用:
System.gc();
System.runFinalization();
这两个方法调用将强制垃圾收集器执行任何无法访问的对象的 finalise() 方法并释放内存。但是软件的性能会显着下降,这是因为垃圾在他自己的线程中运行,并且无法控制,并且取决于垃圾收集器使用的算法可能会导致不必要的过度处理,最好是检查您的代码,因为它必须被破坏,您需要使用垃圾收集器以良好的方式工作。
注意:请记住,这仅在 finalize 方法中不是对象的重新分配时才有效,如果发生这种情况,对象将保持活动状态并且它将具有技术上可能的复活。