【问题标题】:GC overhead limit exceeded in code代码中超出了 GC 开销限制
【发布时间】:2016-09-26 15:08:10
【问题描述】:

我已经写了一个代码。我面临的问题是,当 for 循环的“j”超过 1000 时,我开始收到“超出 GC 开销限制”的错误。如果我将分配的内存增加到 4GB,我可以迭代到 2000 次,之后会出现同样的问题。我想保留这个增加内存的选项作为最后的手段,并想尝试扩展我的代码。编译器突出显示了我放置箭头的语句的问题。 有人可以指导我这里可能出现的错误。 我已经访问过这个问题Error java.lang.OutOfMemoryError: GC overhead limit exceeded

     for (int j=1; j<=num_doc; j++) { 
        List<Integer> list1 = new ArrayList<Integer>(Collections.nCopies(129039, 0));
        BufferedReader fl = new BufferedReader(new FileReader(dataFolder+"file"+ " ("+j+")"+".int"));
        String line1;

        while((line1=fl.readLine()) != null) {

            String[] arr=line1.split(" ");//<---------------------
            line1="";
            int k = Integer.parseInt(arr[0]);
            Arrays.fill(arr, "");
            numb=numb+1;
            int temp=(list1.get(k))+1;
            list1.set(k, temp);
        }
        F_d.add(numb);
        numb=0;
        fl.close();
        ls2d.add(new ArrayList<Integer>(list1));//<---------------------
        list1.clear();
    }

【问题讨论】:

  • 您是否清除了代码中某处的ls2d
  • 是的 ls2d 被使用。我只粘贴了编译器突出显示的那部分代码。
  • list1 已经很大了,所以如果你花时间将它添加到ls2d 而不清除它,它会很快占用大量内存从而导致OOME
  • 很难理解您在这里真正想要实现的目标,但我几乎 100% 肯定有更简单的方法可以实现您的目标,而且只需要一小部分内存。
  • @NicolasFilotto list1.clear 已经存在

标签: java garbage-collection


【解决方案1】:

有两件事可以立即优化以减少内存需求:

        // we don't need all the fragments, taking only the first is fine
        String firstElem=line1.substring(0, line1.indexOf(" "));
        line1=null;// let GC collect this at its convenience
        int k = Integer.parseInt(firstElem);

然后

    // Don't add the copy, add list1 itself
    // You are initing list1 in the beginning of the for cycle anyway
    // and until then nothing happens.
    ls2d.add(list1);//<---------------------
    // list1.clear(); -- since we added list1, we don't clear it anymore

【讨论】:

  • 我进行了这些更改,但错误仍然存​​在
  • @Shahzaib - 发生 OOM 的行是否改变了?
  • 是的,现在我粘贴的代码的 ls2d.add(list1) 出现了 Java 堆空间错误
  • @Shahzaib - 那么至少我的建议奏效了。没有解决其他地方的问题。为了解决其他问题,我需要知道 list1 在非零组件中的“密集”程度? (如果它大部分为零,那么它是稀疏的,我们可以摆脱另一个大内存吞噬者)。
  • @Shahzaib 看,for 循环的每次迭代都会消耗至少 129039 x 4 = 500 kB 的内存。我们可以在不丢失信息的情况下用更少的钱做到这一点吗?
【解决方案2】:

这里有一些减少内存消耗和运行时间的想法。

  • 使用数组而不是 ArrayList - 您似乎没有使用 ArrayList 特定的功能,因此数组会更紧凑且更易于使用
  • 告诉 split 只读取一行的第一个字段

请注意,我删除了所有旨在强制垃圾收集器进行清理的代码,我认为这在这种情况下没有帮助。


 for (int j=1; j<=num_doc; j++) { 
    int[] list1 = new int[129039];

    BufferedReader fl = new BufferedReader(new FileReader(dataFolder+"file"+ " ("+j+")"+".int"));
    String line1;

    while((line1=fl.readLine()) != null) {
        String[] arr=line1.split(" ",2); // Just read first field - see String Javadoc
        int k = Integer.parseInt(arr[0]);
        list[k]=list[k]+1;
        numb=numb+1;
    }
    F_d.add(numb);
    numb=0;
    fl.close();
    ls2d.add(list1);// you'll obviously need to change ls2d's type, or reconvert using Arrays.asList
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-05-21
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-27
    • 2013-07-13
    相关资源
    最近更新 更多