簡體   English   中英

Apache POI XSSFWorkbook內存泄漏

[英]Apache POI XSSFWorkbook memory leak

因此,我正在Java中制作大型質數生成器(借助於JavaFX)。

它使用Apache POI庫(我相信我正在使用v3.17)將結果輸出到Excel電子表格。

此導出邏輯的靜態方法保存在名為ExcelWriter的類中。 基本上,它通過Arraylist參數進行迭代,並使用其內容填充XSSFWorkbook。 后記,FileOutputStream用於實際上使它成為一個excel文件。 這是其中的相關部分:

public class ExcelWriter {

//Configured JFileChooser to make alert before overwriting old files
private static JFileChooser fileManager = new JFileChooser(){
@Override
public void approveSelection(){
    ...
}        
};


private static FileFilter filter = new FileNameExtensionFilter("Excel files","xlsx");
private static boolean hasBeenInitialized = false;



//Only method that can be called externally to access this class's functionality
public static <T extends Object> void makeSpreadsheet
    (ArrayList<T> list,  spreadsheetTypes type, int max, String title, JFXProgressBar progressBar) 
            throws IOException, InterruptedException{
    progressBar.progressProperty().setValue(0);
    switch (type){
        case rightToLeftColumnLimit:
            makeSpreadsheetRightToLeft(list, false, max, title, progressBar);
            break;
       ...
    }
}


static private <T extends Object> void makeSpreadsheetRightToLeft
    (ArrayList<T> list,  boolean maxRows, int max, String title, JFXProgressBar progressBar) 
            throws IOException, InterruptedException{
    initializeChooser();
    XSSFWorkbook workbook = new XSSFWorkbook();
    XSSFSheet sheet = workbook.createSheet("Primus output"); 
    int rowPointer = 0;
    int columnPointer = 0;
    double progressIncrementValue = 1/(double)list.size();

    //Giving the spreadsheet an internal title also
    Row row = sheet.createRow(0);
    row.createCell(0).setCellValue(title);

    row = sheet.createRow(++rowPointer);

    //Making the sheet with a max column limit
    if (!maxRows){            
        for (T number: list){ 
            if (columnPointer == max){
                columnPointer = 0;
                row = sheet.createRow(++rowPointer);
            }
            Cell cell = row.createCell(columnPointer++);
            progressBar.setProgress(progressBar.getProgress() + progressIncrementValue);
            cell.setCellValue(number.toString());             
        }
    }else {
        //Making the sheet with a max row limit
        int columnWrapIndex = (int)Math.ceil(list.size()/(float)max);
        for (T number: list){ 
            if (columnPointer == columnWrapIndex){
                columnPointer = 0;
                row = sheet.createRow(++rowPointer);
            }
            Cell cell = row.createCell(columnPointer++);
            progressBar.setProgress(progressBar.getProgress() + progressIncrementValue);
            cell.setCellValue(number.toString());
        }         
    }
    writeToExcel(workbook, progressBar);


}


static private void writeToExcel(XSSFWorkbook book, JFXProgressBar progressBar) throws IOException, InterruptedException{
    //Exporting to Excel
    int returnValue = fileManager.showSaveDialog(null);

    if (returnValue == JFileChooser.APPROVE_OPTION){
        File file = fileManager.getSelectedFile();

        //Validation logic here


        try{

            FileOutputStream out = new FileOutputStream(file);
            book.write(out);
            out.close();
            book.close();
        }catch (FileNotFoundException ex){

        } 

    }
}
}

之后,我的FXML文檔控制器具有一個buttonListerner,它調用:

longCalculationThread thread = new longCalculationThread(threadBundle);
thread.start();

longcalculationthread創建一個大約一百萬個質數的列表,並使用以下代碼將其導出到ExcelWriter:

private void publishResults() throws IOException, InterruptedException{
    if (!longResults.isEmpty()){
        if (shouldExport) {
            progressText.setText("Exporting to Excel...");
            ExcelWriter.makeSpreadsheet(longResults, exportType, excelExportLimit, getTitle(), progressBar);

    }
   }

問題是,即使在XSSF工作簿中保存工作簿的變量是它所使用的方法的局部變量,也不會在以后收集垃圾。

它占用了大約1.5GB的RAM(我不知道為什么),並且只有在調用另一個巨大的導出時(而不是小的導出)才重新分配該數據。 我的問題不是真的那東西要占用大量RAM,而是即使方法完成后,內存也不會被GC。 這是我的NetBeans配置文件的一些圖片:

制作1000000個素數數組時的正常內存使用情況: 制作1000000個素數數組時的正常內存使用情況

制作工作簿時的大量堆使用 制作工作簿時的大量堆使用

當無法再訪問工作簿時,不會重新分配內存 當無法再訪問工作簿時,不會重新分配內存

使用相同的靜態方法制作新工作簿時出現波動 使用相同的靜態方法制作新工作簿時出現波動

我找到了答案! 我必須使用System.gc()提示GC。 我記得早些時候嘗試過此方法,但是我必須將其調整為仍可訪問該工作簿,因此無法對其進行GC處理。

暫無
暫無

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

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