2016-04-03 152 views
2

私の論文のために(15000)のファイルを読む必要があります。私は開くために、後でそれらを分析するための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ブロックで例外の場合

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

それが引き起こす1つの非常に大きなファイルである可能性があり

OOMは、Javaプロセスのために定義するメモリ設定に基づいています。 OOMが起こっている1つのファイルでのみ実行しようとすると、このファイルがすでにOOMをトリガーしているかどうかを確認できますか? – centic

+0

はい、それは1つの大きなファイル(42メガバイト)であり、作業中のこのファイルをホワイトアウトしています:-)ありがとうございます。 – MichaD

答えて

3

通常、POIには全体のブックがメモリされています。したがって、大きなワークブックには異なるアプローチが必要です。

と書くことができますが、SXSSFを使用することができます。ほとんどの呼び出しは同じですが、特定の行数だけメモリに格納されます。

あなたの場合、です。このために、「イベントドリブン」APIを使用できます。ここでの基本的な考え方は、ワークブックを1つの大きなオブジェクトとして取得しないということです。代わりに、それを読みとるごとにそれを少しずつ得ることができます。そして、自分のデータ構造に望みどおりに保存することができます。あるいは、あなたがそれを読んでそれを処理するだけで、あまり保存することはできません。

これは(読み取るデータの構造によって駆動される)低レベルの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-with-resourcesを使用することをおすすめします。

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

関連する問題