我正在尝试读取 Excel 文件...进行一些更改...保存到新文件。
我创建了带有按钮的小表单...按下按钮..
- 它将加载 Excel 文件并将所有数据加载到我创建的类的数组列表中。
- 它将循环遍历数组列表并更改对象中的一些属性。
- 它将数据保存到新的 Excel 文件中。
- 最后,它将清除数组列表并显示完成消息框。
现在的问题是内存问题。
加载表单后,我可以在 Windows 任务管理器中看到...javaw 正在使用大约 23MB。
在读取和写入 Excel 期间...内存高达 170MB。
清除数组列表后...内存未清除并保持在 150MB 左右。
以下代码附加到按钮单击事件。
MouseListener mouseListener = new MouseAdapter() {
public void mouseReleased(MouseEvent mouseEvent) {
if (SwingUtilities.isLeftMouseButton(mouseEvent)) {
ArrayList<Address> addresses = ExcelFunctions.getExcelData(fn);
for (Address address : addresses){
address.setZestimate(Integer.toString(rnd.nextInt(45000)));
address.setRedfinestimate(Integer.toString(rnd.nextInt(45000)));
}
ExcelFunctions.saveToExcel(ofn,addresses);
addresses.clear();
JOptionPane.showMessageDialog(null, "Done");
}
}
};
该类中读取/Excel文件的代码。
public class ExcelFunctions {
public static ArrayList<Address> getExcelData(String fn)
{
ArrayList<Address> output = new ArrayList<Address>();
try
{
FileInputStream file = new FileInputStream(new File(fn));
//Create Workbook instance holding reference to .xlsx file
XSSFWorkbook workbook = new XSSFWorkbook(file);
//Get first/desired sheet from the workbook
XSSFSheet sheet = workbook.getSheetAt(0);
System.out.println(sheet.getSheetName());
//Iterate through each rows one by one
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext())
{
Row row = rowIterator.next();
int r = row.getRowNum();
int fc= row.getFirstCellNum();
int lc = row.getLastCellNum();
String msg = "Row:"+ r +"FColumn:"+ fc + "LColumn"+lc;
System.out.println(msg);
if (row.getRowNum() > 0) {
Address add = new Address();
Cell c0 = row.getCell(0);
Cell c1 = row.getCell(1);
Cell c2 = row.getCell(2);
Cell c3 = row.getCell(3);
Cell c4 = row.getCell(4);
Cell c5 = row.getCell(5);
if (c0 != null){c0.setCellType(Cell.CELL_TYPE_STRING);add.setState(c0.toString());}
if (c1 != null){c1.setCellType(Cell.CELL_TYPE_STRING);add.setCity(c1.toString());}
if (c2 != null){c2.setCellType(Cell.CELL_TYPE_STRING);add.setZipcode(c2.toString());}
if (c3 != null){c3.setCellType(Cell.CELL_TYPE_STRING);add.setAddress(c3.getStringCellValue());}
if (c4 != null){c4.setCellType(Cell.CELL_TYPE_STRING);add.setZestimate(c4.getStringCellValue());}
if (c5 != null){c5.setCellType(Cell.CELL_TYPE_STRING);add.setRedfinestimate(c5.getStringCellValue());}
output.add(add);
c0=null;c1=null;c2=null;c3=null;c4=null;c5=null;
}
}
workbook.close();
file.close();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
return output;
}
public static void saveToExcel(String ofn, ArrayList<Address> addresses) {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet sheet = workbook.createSheet("Addresses");
Row header = sheet.createRow(0);
header.createCell(0).setCellValue("State");
header.createCell(1).setCellValue("City");
header.createCell(2).setCellValue("Zip");
header.createCell(3).setCellValue("Address");
header.createCell(4).setCellValue("Zestimates");
header.createCell(5).setCellValue("Redfin Estimate");
int row = 1;
for (Address address : addresses){
Row dataRow = sheet.createRow(row);
dataRow.createCell(0).setCellValue(address.getState());
dataRow.createCell(1).setCellValue(address.getCity());
dataRow.createCell(2).setCellValue(address.getZipcode());
dataRow.createCell(3).setCellValue(address.getAddress());
dataRow.createCell(4).setCellValue(address.getZestimate());
dataRow.createCell(5).setCellValue(address.getRedfinestimate());
row++;
}
try {
FileOutputStream out = new FileOutputStream(new File(ofn));
workbook.write(out);
out.close();
workbook.close();
System.out.println("Excel with foumula cells written successfully");
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}}
我无法弄清楚问题出在哪里。
我正在关闭工作簿/输入流/输出流并清除 Arraylist。
最佳答案
您可能没有内存泄漏...
When form is loaded, I can see in windows task manager...javaw is using around 23MB. During read and write excel...memory shoots upto 170MB. After array list is cleared....Memory is not clearing up and stays around 150MB.
这并不描述内存泄漏 - 任务管理器向您显示进程保留的内存 - 而不是应用程序 heap space .
您的 JVM 将分配堆至其配置的最大值,例如 200 MiB。通常,从操作系统分配该内存后,JVM 不会将其归还(经常)。但是,如果您查看堆使用情况(使用 JConsole 或 JVisual VM 等工具),您会发现堆在 GC 之后被回收。
Java如何消耗内存
作为一个非常基本的示例:
图片来源:https://stopcoding.files.wordpress.com/2010/04/visualvm_hfcd4.png
在此示例中,JVM 的最大堆为 1 GiB,并且由于应用程序需要更多内存,因此从操作系统(橙色区域)保留了 400 MiB。
蓝色区域是应用程序实际使用的堆内存。锯齿效应是垃圾收集过程回收未使用的内存的结果。请注意,橙色区域保持相当静态 - 它通常不会随着每个 GC 事件而调整大小...
within few seconds...it shoot upto 800MB and stays there till end....I have not got any memory error
如果发生内存泄漏,您最终会收到内存不足错误。 “泄漏”(至少在 Java 中)是指应用程序占用堆中的内存,但不释放它以供应用程序重用。如果您观察到的内存增长得那么快,但应用程序没有崩溃,您可能会看到内部(在 JVM 中)内存实际上正在被释放和重用。
限制 Java 可以使用的(操作系统)内存
如果您想限制应用程序可以从操作系统保留的内存,您需要配置最大堆大小(通过 -Xmx
选项)以及永久代大小(如果您仍在使用 Java 7 或更早版本)。请注意,JVM 本身使用一些内存,因此在操作系统级别(使用任务管理器等工具)显示的值可能高于您指定的应用程序内存总和。
关于使用 Apache.POI 读写 Excel 的 Java 内存问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34850130/