2016-04-03 6 views
2

Ich muss (15000) Excel-Dateien für meine Diplomarbeit lesen. Ich verwende Apache Poi zu öffnen und sie später zu analysieren, aber nach etwa 5000 Dateien erhalte ich die folgende Ausnahme und Stacktrace:Java Apache-poi, Speicherleck mit Excel-Dateien

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) 

-Code (im Moment nur die Datei öffnen und schließen Sie die Datei):

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();} 
} 

Ich versuchte auch mit OPCPackage.open (Datei) und ich bekam das gleiche Ergebnis.

Was mache ich falsch oder was kann ich tun, um dieses Problem zu lösen? Danke für jede Hilfe.


EDIT: Das gleiche gilt für den Code unten.

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

Es sein könnte sehr große Datei, die eine verursacht OOM basierend auf den Speichereinstellungen, die Sie für Ihren Java-Prozess definieren. Kannst du versuchen, nur mit der einen Datei zu laufen, in der das OOM passiert, und zu sehen, ob diese allein das OOM auslöst? – centic

+0

Ja, es ist eine große Datei (42 MB) und Whiteout diese Datei funktioniert es :-) Danke. – MichaD

Antwort

3

Normalerweise hat POI die gesamte Arbeitsmappe im Speicher. Eine große Arbeitsmappe erfordert also einen anderen Ansatz.

Während Schreiben kann man SXSSF und die meisten Anrufe sind gleich verwenden, es sei denn, dass nur eine bestimmte Anzahl von Zeilen im Speicher befinden.

In Ihrem Fall sind Sie lesen. Dazu können Sie ihre "Event Driven" API verwenden. Die Grundidee ist, dass Sie die Arbeitsmappe nicht als ein riesiges Objekt erhalten. Stattdessen erhalten Sie es stückweise, wie es gelesen wird, und Sie können so viel speichern, wie Sie möchten, in Ihre eigene Datenstruktur. Oder Sie können es einfach verarbeiten, während Sie es lesen und nicht viel sparen.

Da dies eine untergeordnete API ist (die von der Struktur der gelesenen Daten abhängt), gibt es einen Ansatz für XLS und einen anderen Ansatz für XLSX. Sehen Sie sich den POI "How To" page an und finden Sie den Abschnitt mit dem Titel "XSSF and SAX (Event API)".

Das Beispiel zeigt, wie der Wert jeder Zelle zu erfassen, wie es in gelesen wird. (Sie finden die xercesImpl.jar auf dem Bibliothekspfad benötigen.)

3

Im Falle einer Ausnahme in Ihrem ersten try-Block kehren Sie zurück, sodass Sie die Arbeitsmappe nicht schließen würden.

Setzen Sie den Abschluss in einen finally Block.

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(); 
} 

Oder, besser, verwenden Sie Try-mit-Ressourcen.

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

Danke für den Hinweis. Ich habe es versucht, aber ich bekomme die gleiche Ausnahme und Stacktrace nach der gleichen Anzahl von Dateien. – MichaD

+1

Nun, in diesem Fall ist es kein Problem mit dem Code, den Sie gepostet haben :) Sie halten sich wahrscheinlich an Verweise auf Zeug in dem Code, den Sie verwenden, um die Arbeitsmappe zu analysieren - OOM-Fehler manifestieren sich nicht unbedingt an der Stelle, an der das tatsächlich ist Speicherleck tritt auf. –

+0

Das ist der Punkt, den ich nicht verstehe, weil ich nur ein neues xssfworkbook erstelle und es schließe.Ich mache im Moment nichts mit dem Arbeitsbuch. Ich habe den kompletten Code hinzugefügt, den ich ausführe. – MichaD