经过大量的努力,我似乎无法克服获得
的问题我的Java程序中出现超出GC开销限额
错误。
它出现在包含大型字符串操作,许多对象列表和对DB的访问的大型方法中。 我尝试过以下方法:
这个方法是从main调用的:
for(int i=0; i<L; i++) {
cns = new Console(i);
cns.processData();//this is the method
cns=null;
}
当这个循环执行1或2次时,一切正常。对于L&gt; = 3,几乎可以肯定我会得到垃圾收集器错误。
在每次执行方法后,我不应该有 cns = null 的事实,强制GC并释放上一次执行中的所有内容吗?
在将对象设置为null之前,是否还要删除该对象的所有私有属性?也许放一个 Thread.sleep()会在每次循环后强制GC吗?
答案 0 :(得分:0)
实际上没有理由在每个循环结束时将cns
设置为null。无论如何,您在循环开始时将其设置为new Console()
- 如果可以通过将其设置为null来释放任何内容,则还可以通过将其设置为新对象来释放它。
您可以尝试System.gc();
来建议系统进行垃圾回收,但我不知道这是否会对您造成影响或使其恶化。系统已经在尝试垃圾收集 - 如果它不是,你就不会收到这个错误。
您没有准确地向我们展示您如何构建您的字符串,但请记住,+=
并非唯一的罪魁祸首。如果您有类似String s = "Hello " + "to the" + " world";
的内容,那就像将它放在三行并使用+=
一样糟糕。如果这是一个问题,StringBuilder
可能是您的朋友。
您可以在Error java.lang.OutOfMemoryError: GC overhead limit exceeded阅读答案,了解有关如何避免此错误的其他建议。似乎对于某些人来说,当你几乎(但不完全)记忆失去时,它会被触发。因此,增加Java可用的内存量可能(或可能不会)有所帮助。
答案 1 :(得分:0)
基本上,“超出 GC 开销限制”是具有过多可访问数据的症状。堆里塞满了不能被垃圾收集的东西......因为它们不是垃圾! JVM 一次又一次地运行 GC 以尝试腾出空间。最终,它认为垃圾收集花费了太多时间,并放弃了。这是通常正确的做法。
您的问题(和其他答案)中的以下想法不是灵魂。
通过调用 System.gc()
强制 GC 运行无济于事。 GC 已经运行过于频繁。
将 null
分配给 cns
无济于事。它立即获得分配给它的其他东西。此外,没有证据表明 Console
对象占用了大量内存。
(请注意,java.io.Console
类的构造函数不是 public
,因此您的示例在编写时没有意义。也许您实际上是在调用 System.getConsole()
?或者这是一个不同的Console
课?)
在将对象设置为 null
之前清除其私有属性不太可能产生任何影响。如果一个对象不可达,那么它的属性值是不相关的。 GC 甚至不会看它们。
调用 Thread.sleep()
没有任何区别。 GC 在它认为需要时运行。
真正的问题是......你没有解释的东西。
最可能的两种解释 (IMO) 如下:
您的应用程序(或您所在的某个库)在某些数据结构中积累了越来越多的对象,这些对象在 for
循环的单次迭代之后仍然存在。简而言之,您有内存泄漏。
您的应用程序只需要更多内存。例如,如果对 processData
的单个调用需要的内存多于可用内存,则无论您尝试让 GC 做什么,您都会得到 OOME。它不能删除可达对象,而且它显然不能找到足够快的垃圾。
这些问题的解决方案各不相同。
对于第一个,你需要找到存储泄漏;见How to find a Java Memory Leak。 (泄漏可能与未关闭的数据库连接、语句或结果集有关,但我对此表示怀疑。GC 应该查找并收集这些资源……如果它们无法访问。)
对于第二个,您需要修改程序以使其需要更少(可访问的)内存,或者您需要增加 JVM 的堆大小。
对于前者,一种可能性是在将输出写入 OutputStream
、Writer
或类似内容之前,您正在构建一个巨大的字符串来表示输出。如果直接写入输出接收器,则可以节省内存。