在此代码段中,我使用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;
}
答案 0 :(得分:3)
首先,我注意到使用任务管理器(Windows)或活动监视器(Mac)进行监视是一项愚蠢的工作。这些工具显示的是保留的堆空间(而不是已使用的堆空间)。因此,当我使用NetBeans分析监视应用程序的内存使用时,我注意到GC可以很好地工作并释放堆内存。
此外,取消引用Workbook
和InputStream
对象(使用=null;
)可加速GC执行。
那之后,我的问题变了。
关闭这些流后,GC运行良好,并且已用的堆空间减少了。但是,保留的堆空间将保持不变并且不会减少,如下图所示:
我看了this article。总之,您需要使用以下JVM参数:
-XX:MinHeapFreeRatio
-XX:MaxHeapFreeRatio
我设置了-XX:MaxHeapFreeRatio=40
,过了一会儿,释放了保留的堆空间。
答案 1 :(得分:-1)
尝试其中两个建议的解决方案,并让我们知道其中是否有任何帮助。
对工作簿和inputStream使用finalize()而不是close()。
在关闭工作簿和inputStream之后,将它们都设置为null,然后调用System.gc();