关闭java InputStream后未释放内存

时间:2018-08-27 09:26:22

标签: java memory garbage-collection out-of-memory inputstream

在此代码段中,我使用Apache POI库加载了大小为10MB的Excel文件。这将消耗近2GB的内存。 遍历所有行之后,我终于调用了close方法。但是,似乎GC不能释放此流和对象占用的空间。而且仍在使用2GB + 400MB的内存。

有什么想法吗?

这是我的代码:

public List<Meter> loadFile(File excelFile) throws IOException, InvalidFormatException {
    List<Meter> allMeters = new ArrayList<>();
    InputStream inputStream = new FileInputStream(excelFile);
    XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
    Sheet sheet1 = workbook.getSheetAt(0);
    Iterator<Row> rows_sheet1 = sheet1.iterator();
    if (rows_sheet1.hasNext()) {
        rows_sheet1.next(); //skip header
    }

    while (rows_sheet1.hasNext()) {
        try {
            Row currentRow = rows_sheet1.next();
            Cell meterNoCell = currentRow.getCell(0);
            Cell startPeriodCell = currentRow.getCell(1);
            Cell endPeriodCell = currentRow.getCell(2);
            Cell previousConsumption = currentRow.getCell(3);
            Cell currentConsumption = currentRow.getCell(4);
            Cell periodConsumptionCell = currentRow.getCell(5);

            meterNoCell.setCellType(CellType.STRING);
            startPeriodCell.setCellType(CellType.STRING);
            endPeriodCell.setCellType(CellType.STRING);

            //Reading values from above_defined cells and filling allMeters list (defined at the begining of the function).
            //......
            //Done
        }
        catch (Exception ex) {
            Logger.getLogger(MetersList.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    workbook.close();
    inputStream.close();
    return allMeters;
}

2 个答案:

答案 0 :(得分:3)

首先,我注意到使用任务管理器(Windows)或活动监视器(Mac)进行监视是一项愚蠢的工作。这些工具显示的是保留的堆空间(而不是已使用的堆空间)。因此,当我使用NetBeans分析监视应用程序的内存使用时,我注意到GC可以很好地工作并释放堆内存。

此外,取消引用WorkbookInputStream对象(使用=null;)可加速GC执行。

那之后,我的问题变了。

关闭这些流后,GC运行良好,并且已用的堆空间减少了。但是,保留的堆空间将保持不变并且不会减少,如下图所示:

Fig. 1 我看了this article。总之,您需要使用以下JVM参数:

-XX:MinHeapFreeRatio
-XX:MaxHeapFreeRatio

我设置了-XX:MaxHeapFreeRatio=40,过了一会儿,释放了保留的堆空间。

答案 1 :(得分:-1)

尝试其中两个建议的解决方案,并让我们知道其中是否有任何帮助。

  1. 对工作簿和inputStream使用finalize()而不是close()。

  2. 在关闭工作簿和inputStream之后,将它们都设置为null,然后调用System.gc();