簡體   English   中英

使用Apache.POI讀取Excel的Java內存問題

[英]Java Memory issue using Apache.POI to read write Excel

我正在嘗試讀取Excel文件...進行一些更改...保存到新文件。

我已經創建了帶有按鈕的小表格。

  • 它將加載Excel文件並將所有數據加載到我創建的類的Array列表中。
  • 它將遍歷數組列表並更改對象中的幾個屬性。
  • 它將數據保存到新的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");
            }
        }
    };


該類中Reading / 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。

您可能沒有內存泄漏...

加載表單后,我可以在Windows任務管理器中看到... javaw正在使用約23MB。 在讀寫excel期間...內存拍攝高達170MB。 清除陣列列表后...。內存沒有清除,並保持在150MB左右。

這並不描述內存泄漏-任務管理器向您顯示進程保留的內存-而不是應用程序堆空間

您的JVM將最多分配堆,使其達到配置的最大值,例如200 MiB。 通常,從操作系統分配了此內存后,JVM不會(經常)將其退還給您。 但是,如果您查看堆的使用情況(使用諸如JConsole或JVisual VM之類的工具),則會看到在GC之后回收了堆。

Java如何消耗內存

作為一個非常基本的示例:

JVisual VM內存

圖片來源: https : //stopcoding.files.wordpress.com/2010/04/visualvm_hfcd4.png

在此示例中,JVM的最大堆容量為1 GiB,並且由於應用程序需要更多內存,因此從OS(橙色區域)保留了400 MiB。

藍色區域是應用程序使用的實際堆內存。 鋸齒效應是垃圾回收過程回收未使用的內存的結果。 請注意,橙色區域保持相當靜態-通常不會隨着每個GC事件而調整大小...

在幾秒鍾之內...它可以拍攝高達800MB的內存,直到結束....我沒有出現任何內存錯誤

如果發生內存泄漏,最終將出現內存不足錯誤。 “泄漏”(至少在Java中)是指應用程序占用堆中的內存,但不釋放內存以供應用程序重用。 如果觀察到的內存迅速增加,但是應用程序沒有崩潰,則您可能會發現內部(在JVM中)內存實際上已被釋放和重用。

限制Java可以使用多少(OS)內存

如果要限制應用程序可以從OS保留的內存,則需要配置最大堆大小(通過-Xmx選項)以及永久生成大小(如果仍在使用Java 7或更早版本)。 請注意,JVM本身會使用一些內存,因此在OS級別顯示的值(使用任務管理器之類的工具)可能會高於您指定的應用程序內存總和。

在新版本的poi中,他們使用Java流來解決內存問題。 看一看

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM