关闭java InputStream后未释放内存

关闭java InputStream后未释放内存,java,memory,garbage-collection,out-of-memory,inputstream,Java,Memory,Garbage Collection,Out Of Memory,Inputstream,在这段代码中,我使用ApachePOI库加载了一个10MB大小的excel文件。这将消耗近2GB的内存。 迭代了所有行之后,我最终调用close方法。然而,GC似乎并没有释放这个流和对象所消耗的空间。并且仍然使用2GB+400MB的内存 有什么想法吗 这是我的密码: public List<Meter> loadFile(File excelFile) throws IOException, InvalidFormatException { List<Meter>

在这段代码中,我使用ApachePOI库加载了一个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;
}
public List loadFile(File excelFile)抛出IOException、InvalidFormatException{
List allMeters=new ArrayList();
InputStream InputStream=新文件InputStream(excelFile);
XSSF工作簿=新XSSF工作簿(inputStream);
工作表sheet1=工作簿。getSheetAt(0);
迭代器行_sheet1=sheet1.Iterator();
如果(行数为1.hasNext()){
行_sheet1.next();//跳过标题
}
while(rows\u sheet1.hasNext()){
试一试{
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);
单元电流消耗=currentRow.getCell(4);
单元周期消耗单元=currentRow.getCell(5);
meterNoCell.setCellType(CellType.STRING);
startPeriodCell.setCellType(CellType.STRING);
endPeriodCell.setCellType(CellType.STRING);
//从上面定义的单元格中读取值并填充allMeters列表(在函数开始时定义)。
//......
//完成
}
捕获(例外情况除外){
Logger.getLogger(MetersList.class.getName()).log(Level.SEVERE,null,ex);
}
}
workbook.close();
inputStream.close();
返回所有仪表;
}

尝试两种建议的解决方案,如果其中任何一种对您有帮助,请告知我们

  • 对工作簿和inputStream使用finalize()而不是close()

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


  • 尝试两种建议的解决方案,并让我们知道其中任何一种是否对您有所帮助

  • 对工作簿和inputStream使用finalize()而不是close()

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


  • 首先,我注意到使用任务管理器(Windows)或活动监视器(Mac)进行监视是一项愚蠢的工作。这些工具显示的是保留的堆空间(而不是使用的堆空间)。因此,当我使用NetBeans评测监控应用程序的内存使用情况时,我注意到GC工作得非常好,并且释放了堆内存

    此外,取消引用
    工作簿
    InputStream
    对象(其中
    =null;
    )加速了GC的执行

    从那以后,我的问题变了

    在我关闭这些流之后,GC工作良好,使用的堆空间减少。但是,保留的堆空间将保持不变且不会减少,如下图所示:

    我看了一眼。总之,您需要使用以下JVM参数:

    -XX:MinHeapFreeRatio
    -XX:MaxHeapFreeRatio
    

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

    首先,我注意到使用任务管理器(Windows)或活动监视器(Mac)进行监视是一项愚蠢的工作。这些工具显示的是保留的堆空间(而不是使用的堆空间)。因此,当我使用NetBeans评测监控应用程序的内存使用情况时,我注意到GC工作得非常好,并且释放了堆内存

    此外,取消引用
    工作簿
    InputStream
    对象(其中
    =null;
    )加速了GC的执行

    从那以后,我的问题变了

    在我关闭这些流之后,GC工作良好,使用的堆空间减少。但是,保留的堆空间将保持不变且不会减少,如下图所示:

    我看了一眼。总之,您需要使用以下JVM参数:

    -XX:MinHeapFreeRatio
    -XX:MaxHeapFreeRatio
    

    我设置了
    -XX:MaxHeapFreeRatio=40
    ,一段时间后,保留的堆空间被释放。

    如何测量内存使用率?进行内存转储并分析,以了解内存中剩余的对象类型请注意,每次
    关闭()
    操作后,GC不会自动调用,它由JVM调用,调用取决于它的GC设置。您可以使用
    jvisualvm
    监视Java进程,在那里您可以找到“执行GC”按钮。请尝试一下,您会发现GC后堆使用率会降低。@Arman Task manager不提供有关GC活动的任何信息-JVM将在操作系统内存中保留一些空间,并根据需要进行扩展。但是java进程使用的内存包括已使用和未使用的堆空间(即,GC后不会减少)。您需要以不同的方式监视GC,例如使用jvisualvm或飞行记录器。取消对inputStream和工作簿的引用可以更早地触发GC,试一试。如何衡量内存使用情况?进行内存转储并分析它,以了解内存中剩余的对象类型请注意,GC不会在每次
    close()
    操作后自动调用,它是由JVM调用的,调用取决于它的GC设置。您可以使用
    jvisualvm
    监视Java进程,在那里您可以找到“执行GC”按钮。请尝试一下,您会发现GC后堆使用率会降低。@Arman Task manager不提供有关GC活动的任何信息-JVM将在操作系统内存中保留一些空间,并根据需要进行扩展。但是java进程使用的内存包括已使用和未使用的堆空间(即,GC后不会减少)。您需要以不同的方式监视GC,例如使用jvisualvm或飞行记录器。取消对inputStream和工作簿的引用可以更早地触发GC,请尝试一下。无需使用
    finalize()
    ,而且应该避免使用它。参见J.Bloch的“高效Java”