Java Apache-poi,内存泄漏与excel文件

时间:2016-04-03 19:11:44

标签: java excel memory-leaks apache-poi

我需要为我的论文阅读(15000)excel文件。我使用apache poi打开并稍后分析它们但是在大约5000个文件之后我得到了以下异常和堆栈跟踪:

Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3044)
at org.apache.xmlbeans.impl.store.Cur$CurLoadContext.attr(Cur.java:3065)
at org.apache.xmlbeans.impl.store.Locale$SaxHandler.startElement(Locale.java:3263)
at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.reportStartTag(Piccolo.java:1082)
at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseAttributesNS(PiccoloLexer.java:1822)
at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseOpenTagNS(PiccoloLexer.java:1521)
at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.parseTagNS(PiccoloLexer.java:1362)
at org.apache.xmlbeans.impl.piccolo.xml.PiccoloLexer.yylex(PiccoloLexer.java:4682)
at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yylex(Piccolo.java:1290)
at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.yyparse(Piccolo.java:1400)
at org.apache.xmlbeans.impl.piccolo.xml.Piccolo.parse(Piccolo.java:714)
at org.apache.xmlbeans.impl.store.Locale$SaxLoader.load(Locale.java:3479)
at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1277)
at org.apache.xmlbeans.impl.store.Locale.parseToXmlObject(Locale.java:1264)
at org.apache.xmlbeans.impl.schema.SchemaTypeLoaderBase.parse(SchemaTypeLoaderBase.java:345)
at org.apache.poi.POIXMLTypeLoader.parse(POIXMLTypeLoader.java:92)
at org.openxmlformats.schemas.spreadsheetml.x2006.main.WorksheetDocument$Factory.parse(Unknown Source)
at org.apache.poi.xssf.usermodel.XSSFSheet.read(XSSFSheet.java:173)
at org.apache.poi.xssf.usermodel.XSSFSheet.onDocumentRead(XSSFSheet.java:165)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.parseSheet(XSSFWorkbook.java:417)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.onDocumentRead(XSSFWorkbook.java:382)
at org.apache.poi.POIXMLDocument.load(POIXMLDocument.java:178)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:249)
at org.apache.poi.xssf.usermodel.XSSFWorkbook.<init>(XSSFWorkbook.java:302)
at de.spreadsheet_realtions.analysis.WorkbookAnalysis.analyze(WorkbookAnalysis.java:18)

代码(此时只需打开文件并关闭文件):

public static void main(String[] args) {
    start();
}

public void start(){
    File[] files = getAllFiles(Config.folder);
    ZipSecureFile.setMinInflateRatio(0.00);
    for(File f: files){
        analyze(f);
    }
}

public void analyze(File file){
    Workbook  workbook = null;
    try {
        workbook = new XSSFWorkbook(file); //line 18
    } catch (Exception e1) {e1.printStackTrace(); return;}
//      later would be here the code to analyze the workbook
    try {
        workbook.close();
    } catch (Exception e) {e.printStackTrace();}
}

我也尝试使用OPCPackage.open(文件),我得到了相同的结果。

我做错了什么或我该怎么做才能解决这个问题?谢谢你的帮助。

编辑: 以下代码也是如此。

try (XSSFWorkbook workbook = new XSSFWorkbook(file)){
} catch (Exception e1) {e1.printStackTrace(); return;}

2 个答案:

答案 0 :(得分:4)

通常,POI在整个内存中都有整个工作簿。因此,大型工作簿需要采用不同的方法。

时,可以使用SXSSF并且大多数调用都是相同的,除了内存中只有一定数量的行。

在您的情况下,您正在阅读。为此,您可以使用他们的“事件驱动”API。这里的基本思想是,您不会将工作簿作为一个巨大的对象。相反,你可以随意阅读它,并且你可以根据自己的意愿将其保存到自己的数据结构中。或者,您可以在阅读时简单地处理它而不是非常节省。

由于这是一个较低级别的API(由正在读取的数据结构驱动),因此XLS有一种方法,XLSX有一种不同的方法。查看POI "How To" page,找到标题为“XSSF和SAX(事件API)”的部分。

该示例演示了如何在读入时检测每个单元格的值。 (你的库路径上需要xercesImpl.jar。)

答案 1 :(得分:3)

如果您的第一个try块出现异常,则返回,因此您不会关闭该工作簿。

将关闭放在Workbook workbook = null; try { workbook = new XSSFWorkbook(file); //line 18 // later would be here the code to analyze the workbook } catch (Exception e1) { e1.printStackTrace(); return; } finally { if (workbook != null) workbook.close(); } 区块中。

try (XSSFWorkbook workbook = new XSSFWorkbook(file) {
  // later would be here the code to analyze
} catch (Exception e1) {
  e1.printStackTrace();
}
// No need for explicit close.

或者,更好的是,使用try-with-resources。

{{1}}