避免“超出GC开销限制”错误

时间:2017-10-28 21:43:27

标签: java garbage-collection limit overhead

经过大量的努力,我似乎​​无法克服获得

的问题
  

超出GC开销限额

我的Java程序中出现

错误。

它出现在包含大型字符串操作,许多对象列表和对DB的访问的大型方法中。 我尝试过以下方法:

  1. 在使用每个ArrayList之后,我添加了: list = new ArrayList<>();列表= NULL;
  2. 表示字符串,而不是例如50追加(str + =“....”)我尝试用总文本附加一个
  3. 在每次数据库访问后,我关闭语句和resultSets。
  4. 这个方法是从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吗?

2 个答案:

答案 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 以尝试腾出空间。最终,它认为垃圾收集花费了太多时间,并放弃了。这是通常正确的做法。


您的问题(和其他答案)中的以下想法不是灵魂。

  1. 通过调用 System.gc() 强制 GC 运行无济于事。 GC 已经运行过于频繁

  2. null 分配给 cns 无济于事。它立即获得分配给它的其他东西。此外,没有证据表明 Console 对象占用了大量内存。

    (请注意,java.io.Console 类的构造函数不是 public,因此您的示例在编写时没有意义。也许您实际上是在调用 System.getConsole()?或者这是一个不同的Console 课?)

  3. 在将对象设置为 null 之前清除其私有属性不太可能产生任何影响。如果一个对象不可达,那么它的属性值是不相关的。 GC 甚至不会看它们。

  4. 调用 Thread.sleep() 没有任何区别。 GC 在它认为需要时运行。


真正的问题是......你没有解释的东西。

最可能的两种解释 (IMO) 如下:

  • 您的应用程序(或您所在的某个库)在某些数据结构中积累了越来越多的对象,这些对象在 for 循环的单次迭代之后仍然存在。简而言之,您有内存泄漏。

  • 您的应用程序只需要更多内存。例如,如果对 processData 的单个调用需要的内存多于可用内存,则无论您尝试让 GC 做什么,您都会得到 OOME。它不能删除可达对象,而且它显然不能找到足够快的垃圾。

这些问题的解决方案各不相同。

  • 对于第一个,你需要找到存储泄漏;见How to find a Java Memory Leak。 (泄漏可能与未关闭的数据库连接、语句或结果集有关,但我对此表示怀疑。GC 应该查找并收集这些资源……如果它们无法访问。)

  • 对于第二个,您需要修改程序以使其需要更少(可访问的)内存,或者您需要增加 JVM 的堆大小。

    对于前者,一种可能性是在将输出写入 OutputStreamWriter 或类似内容之前,您正在构建一个巨大的字符串来表示输出。如果直接写入输出接收器,则可以节省内存。

相关问题