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

问题描述

我收到此错误消息: 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. 增加堆的大小,并不断增加直到没有OOMEs。如果那意味着您需要一台具有更多RAM的计算机来运行您的应用程序,请购买一台。

  2. 如果您使用的API具有用于写入数据的 streaming 模式,请使用该模式。或寻找此API的另一种支持流传输的API。

  3. 也许有一个非流式电子表格API,它使用的内存少于当前使用的内存。 (请参阅@Holger的评论。)

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

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


here描述了POI的流版本。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...