2016-04-03 139 views
2

我需要读取(15000)excel文件以供论文学习。我使用的Apache POI打开以后对它们进行分析,但之后在5000左右的文件我得到以下异常和堆栈跟踪:Java Apache-poi,excel文件内存泄漏

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;} 
+0

这可能是一个非常大的文件,该文件会导致OOM基于您为java进程定义的内存设置。你可以尝试只运行OOM发生的一个文件,看看这一个单独是否已经触发了OOM? – centic

+0

是的,它是一个大文件(42mb),并且正在运行这个文件:-)谢谢。 – MichaD

回答

3

通常,POI在内存中具有整个工作簿。所以,一本大型的工作手册需要不同的方法。

虽然,但可以使用SXSSF和大多数调用是相同的,除了只有一定数量的行在内存中。

在你的情况,你是阅读。为此,您可以使用他们的“事件驱动”API。这里的基本想法是,你不会将工作簿看作一个巨大的对象。相反,当它被读取时,你可以将其零碎地分解,并且可以根据自己的需要将其存储到自己的数据结构中。或者,您可以在阅读时简单处理它,而不是节省很多。

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

这个例子演示了如何为它在读取检测每一单元的值。 (你需要的xercesImpl.jar库路径上。)

3

如果在第一次尝试块中出现异常,则返回,所以不会关闭工作簿。

将闭合放在finally块中。

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. 
+0

感谢您的提示。我试过了,但是在相同数量的文件后,我得到了相同的异常和堆栈跟踪。 – MichaD

+1

那么,在这种情况下,它不是你发布的代码的问题:)你可能会持续引用你用来分析工作簿的代码中的东西 - OOM失败并不一定在实际发生的地方内存泄漏正在发生。 –

+0

这是我不明白的地方,因为我只创建一个新的xssfworkbook并关闭它。目前,我对这本工作簿没有做任何事情。我添加了我执行的完整代码。 – MichaD