2011-12-28 46 views
3

以下のように私はJavaを使用してZIPファイルを読んでいます:私はメモリ不足エラーを取得していますJavaで巨大なZipファイルを読み込む - メモリ不足エラー

Enumeration<? extends ZipEntry> zes=zip.entries(); 
    while(zes.hasMoreElements()) { 
     ZipEntry ze=zes.nextElement(); 
     // do stuff.. 
    } 

、zipファイルのサイズは160メガバイト程度です。スタックトレースは以下の通りです:

Exception in thread "Timer-0" java.lang.OutOfMemoryError: Java heap space 
at java.util.zip.InflaterInputStream.<init>(InflaterInputStream.java:88) 
at java.util.zip.ZipFile$1.<init>(ZipFile.java:229) 
at java.util.zip.ZipFile.getInputStream(ZipFile.java:229) 
at java.util.zip.ZipFile.getInputStream(ZipFile.java:197) 
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.zipFilePass2(DatToInsertDBBatch.java:250) 
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.processCompany(DatToInsertDBBatch.java:206) 
at com.aesthete.csmart.batches.batchproc.DatToInsertDBBatch.run(DatToInsertDBBatch.java:114) 
at java.util.TimerThread.mainLoop(Timer.java:534) 
at java.util.TimerThread.run(Timer.java:484) 

私は私のヒープサイズを増やすことなく、大きなzipファイルの内容を列挙する方法を教えてください。また、内容を列挙せずにこのような単一のファイルにアクセスすると、次のようになります。

ZipFile zip=new ZipFile(zipFile); 
ZipEntry ze=zip.getEntry("docxml.xml"); 

次に、メモリ不足エラーが発生しません。なぜこれが起こるのですか? ZipファイルはZipエントリをどのように処理しますか?もう1つのオプションは、ZIPInputStreamを使用することです。それは小さなメモリフットプリントを持っていますか?私は彼らに

Enumeration<? extends ZipEntry> zes=zip.entries(); 
    while(zes.hasMoreElements()) { 
     ZipEntry ze=zes.nextElement(); 
     S3Object s3Object=new S3Object(bkp.getCompanyFolder()+map.get(ze.getName()).getRelativeLoc()); 
      s3Object.setDataInputStream(zip.getInputStream(ze)); 
      s3Object.setStorageClass(S3Object.STORAGE_CLASS_REDUCED_REDUNDANCY); 
      s3Object.addMetadata("x-amz-server-side-encryption", "AES256"); 
      s3Object.setContentType(Mimetypes.getInstance().getMimetype(s3Object.getKey())); 
      s3Object.setContentDisposition("attachment; filename="+FilenameUtils.getName(s3Object.getKey())); 
      s3objs.add(s3Object); 
    } 
を取得した後、私はZIPエントリを処理する方法についてより多くの情報を提供する:私は、Amazonクラウド(613メガバイトのRAM)

EDIT上のマイクロEC2インスタンス上で、最終的にこのコードを実行する必要があります

私はzipinputstreamをzipentryから取得し、それをS3オブジェクトに格納します。私はリスト内のすべてのS3Objectを収集し、最終的にそれらをAmazon S3にアップロードします。 Amazon S3を知らない人にとっては、ファイルストレージサービスです。 HTTP経由でファイルをアップロードします。

これは起こっているすべての個々の入力ストリームを収集していると思いますか?もし私がそれをバッチアップするのに役立つでしょうか?一度に100の入力ストリームのように?または、私はそれを最初に解凍し、圧縮されていないファイルを使用してストリームを格納するよりもアップロードする方が良いでしょうか?

+0

Micro EC2インスタンスタイプは、大きなファイルの解凍には適していません。これは非常に短い期間のCPU作業しかサポートしません。解凍に2〜5秒以上かかる場合は、Microインスタンスでは非常に簡単ですが、これは動作しません(tm)。 [.NET Frameworkのインストールのようなものでも、CPUを使用するため、.NETフレームワークのインストールには30分かかります] –

+0

Kieren、現時点では2GMのローカルubuntuサーバー上で実行していますRAM :)。ここで失敗した場合、私はそれがマイクロインスタンス上で動作しないことを確信しています。しかし、いったんCodoの提案を使って修正すれば、まだ問題はあると思いますか?私がやっているのは、S3からzipファイルをダウンロードし、解凍してJavaバッチプログラムでS3にアップロードすることです。それはCPU集約的でしょうか?また、同じインスタンスでtomcatとmysql dbを実行しています。それは悪くなるだろうか? – sethu

+0

10秒以下であれば、頻繁に行う必要がない限り、OKになります。 10を超えると、インスタンスに使用可能なCPUが非常に短くなり、数分かかり、インスタンス全体が遅くなります。 –

答えて

2

ZIPファイルを処理しているためにメモリ不足例外が発生することはほとんどありません。 JavaクラスZipFileZipEntryには、613 MBのメモリをいっぱいにするものは含まれていません。

あなたのメモリを枯渇させる原因は、ZIPアーカイブの圧縮解除されたファイルをメモリに保存することです。さらに悪いことに、メモリを大量に消費するXML DOMとして保存することです。

別のZIPライブラリに切り替えることはほとんど役に立ちません。代わりにZIPアーカイブとストリームのようなインクルードされたファイルを処理し、一度にメモリ内の各ファイルの限られた部分だけを保持するようにコードを変更する必要があります。

ところで、の巨大なのZIPファイル(小さなファイルが多数あるか大きなファイルがいくつか入っていますか?)と、各ZIPエントリで何をするかについての詳しい情報を提供できるといいですね。

更新:追加情報については、

感謝。あなたがZIPファイルの内容をメモリに保持しているように見えます(これは、私が知らないS3Objectクラスの実装に多少依存しますが)。

あなた自身を提案するときに、ある種のバッチ処理を実装するのが最善でしょう。たとえば、圧縮された各ZIPエントリのサイズを合計し、合計サイズが100 MBを超えるたびにファイルをアップロードすることができます。

+0

答えをありがとう。あなたが正しいと確信しています。私はzipファイルをどのように処理しているかについての詳細を私の質問に編集しました。あなたはそれを確認してください。 – sethu

+0

また、ファイルの数は多いが、各ファイルは小さいです。最大サイズは5MBです。主に小さなpdf形式とExcel文書とdoc文書。 – sethu

+0

追加情報をありがとう。私は私の答えを更新しました。 – Codo

0

JVMのデフォルトサイズは64MBです。 コマンドラインで大きなサイズを指定する必要があります。 -Xmxスイッチを使用します。例えば。 -Xmx256m

+0

残念ながら、私のRAMのサイズが限られているので、私はそれを行うことはできません。実際には最大613 MBです。 – sethu

+0

JavaチュートリアルにはZipファイル処理に関する素敵なセクションがあります。 http://java.sun.com/developer/technicalArticles/Programming/compression/ – Fortyrunner

+0

Javaチュートリアルのリンクは、一般的なOracle Javaページへのリンクです。誰でも更新されたURLを持っていますか? – Coke

0

実際、java.util.zip.ZipFileにはsize()メソッドがありますが、インデックスでエントリにアクセスするメソッドはありません。多分あなたは別のZIPライブラリを使う必要があります。私が覚えているように、私はかなり大きいアーカイブでTrueZIPを使用しました。

1

私はZipFileクラスを使用しています。おそらく使用法ZipInputStreamは、(私が望むように)エントリによって使用されるメモリリソースを解放する 'closeEntry()'メソッドを持っているので、より良いオプションになります。しかし、私はそれを前に使用していない、それは単なる推測です。

関連する問題