如何改进我的代码以避免 GC 开销限制错误?

How can I improve my code to avoid GC overhead limit error?

我收到此错误消息: java.lang.OutOfMemoryError:超出 GC 开销限制

在此代码的 catch 块中:

try (BufferedReader br = new BufferedReader(new FileReader(fileName))) 
    {
        System.out.println("Starting try block");
        
        String line;
        Row row;
        Cell cell;
        int rowIndex = 0;
        while ((line = br.readLine()) != null) 
        {
            row = sheet.createRow(rowIndex);
            String[] tokens = line.split("[|]");
            for(int iToken = 0; iToken < tokens.length; iToken++) 
            {
                cell = row.createCell(iToken);
                cell.setCellValue(tokens[iToken]);
            }
            rowIndex++;
        }
    } 
    catch(Throwable e) 
    {
        e.printStackTrace();
    }

我正在阅读的文件是大型 txt 文件 (~90000KB)。 在 运行 时间将 VM 内存增加到 2048K 后,我不再收到 HeapSize 错误,但开始收到 GC 错误。 如何修改代码以避免GC错误?

我猜测 SheetRowCell 是来自某些 Java 电子表格 API 的 类。

坏消息来了。

问题是您的代码正在构建一个大型数据结构来表示内存中的电子表格,然后将其写入文件。显然数据结构大于您的 JVM 堆所能容纳的。

第二个问题是,如果你继续使用前面提到的API这种方式,你将无法降低内存占用。

有几种方法可以解决这个问题:

  1. 增加堆大小,并不断增加直到没有 OOME。如果这意味着您需要一台具有更多 RAM 的机器来 运行 您的应用程序,那就买一台吧。

  2. 如果您使用的 API 具有用于写入数据的 streaming 模式,请使用该模式。或者寻找支持流式传输的 API 替代方案。

  3. 可能有一个 non-streaming 电子表格 API 使用的内存少于您当前使用的电子表格。 (参见@Holger 的评论。)

  4. 不生成电子表格。电子表格是 (IMO) 一种低效的数据表示方式。相反,将数据输出为 CSV 文件、JSON 文件、XML 文件或任何其他可以轻松流式传输的格式。

  5. 如果“业务类型”坚持电子表格,您可以将数据输出为 CSV 文件,然后使用外部工具从 CSV 文件创建电子表格。


POI 的流媒体版本描述here