2012-05-10 3 views
0

大きなファイル(> 150MB)を読み込み、ファイルの内容をByteArrayOutputStreamとして返します。これは私のコードです...ファイルを読み込み(> 150MB)、ファイルの内容をByteArrayOutputStreamとして返します。

private ByteArrayOutputStream readfileContent(String url) throws IOException{ 

    log.info("Entering readfileContent "); 
    ByteArrayOutputStream writer=null; 
    FileInputStream reader=null; 

    try{ 
     reader = new FileInputStream(url); 
     writer = new ByteArrayOutputStream(); 

     byte[] buffer = new byte[1024]; 

     int bytesRead = reader.read(buffer); 
     while (bytesRead = > -1) { 
      writer.write(buffer, 0, bytesRead); 
      buffer = new byte[1024]; 
     } 

    } 
    finally { 
     writer.close(); 
    } 

    log.info("Exiting readfileContent "); 
    return writer; 
} 

私はjava.lang.OutOfMemoryError: Java heap space exceptionを取得しています。私は、Javaヒープサイズを増加しようとしましたが、それはまだ発生します。誰かがこの問題を支援してくれますか?

+1

しないでください。ファイルが大きすぎるため、一度にメモリに読み込めません。なぜあなたはByteArrayOutputStreamが必要だと思いますか?発信者はこのストリームで何をしますか?なぜFileInputStreamを返して、呼び出し元にそれを読み込ませないのですか? – Cheeso

+0

チャンク内のファイルの内容を読むことができます。 – Rakesh

+0

サイドノート:1. 'in!= null'は冗長です - ' in'は決して 'null'になることはありません。 2.あなたが「長さ」でやっているのは、ひどくひどいものです。 –

答えて

0

あなたのアプローチでは、ファイルと少なくとも同じメモリ量を使用しますが、ByteArrayOutputStreamはバイト配列を記憶域として使用しているため、150,000回(150メガ/ 1024kバッファ)のサイズを変更する必要があります効率的ではありません。ヒープサイズをファイルサイズの2倍にして、bufのサイズをもっと大きくすると実行可能になるかもしれませんが、他のポスターが言っているように、ファイルを読み込むのではなく、ファイルを読み込む方がはるかに優れていますストリングとして。

+1

最悪の場合の要件は3 *サイズです - 古いものと新しいものの両方の配列共存しなければならず、2 *サイズは連続したヒープチャンクとして利用可能でなければなりません。これはまだ空きメモリがたくさんある場合でも失敗する可能性があります。 –

+0

いいえ - 正しくありません。最悪の場合はあなたが想定しているよりも悪いです。私は、Javaのメモリアロケータを知らないが、あなたがバッファを割り当てるときに、私はそれが単に "正確に"適切なサイズに十分なメモリを割り当てていないと思う。多くの場合、アロケータは2の累乗であるチャンク、または他のチャンクサイズのチャンクを返します。したがって、最悪の場合のシナリオは5倍以上になる可能性があります。あなたは確信が持てません。いずれにせよ、あなたの結論は正しい - それはあなたがheapsizeに何をしても、依然としてOOMEの対象となります。ストリーミングは解決策です。 – Cheeso

1

BufferedInputStreamを返信し、発信者にそれを読むようにしてください。あなたは、ファイル全体をByteArrayOutputStreamとしてメモリにコピーしています。

あなたの質問にはファイルの内容で何かしたいのですか?それがなければ、我々は推測することしかできない。コメントアウトされたServletOutputStreamがあります。元々これに書きたいのですか?この代わりにByteArrayOutputStreamに書き込むことが有効であるはずです。

+0

ByteArrayOutputStreamとしてのファイルコンテンツFAST ESP –

0

読み取るバイト数がわかっているので、サイズがByteArrayOutputStreamであるため、時間とスペースを節約できます。これにより、ByteArrayOutputStreamバッキングストレージを「増やす」ための時間とスペースのオーバーヘッドが節約されます。 (私はコードを見ていませんが、おそらくStringBuilderと同じ戦略を使用しています;つまり、それがなくなるたびに割り当てを倍増させます。その戦略は、ピーク時に最大3倍のファイルサイズを使用する可能性があります)

(そして、率直に言って、あなたはサイズがやや無意味なようでわかっているときByteArrayOutputStreamに出力を置く。ただ、十分なバイト配列はビッグ割り当て、そのに直接お読みください。)

それとは別に、答えはあなたがする必要があるということですヒープを大きくする。

+0

のファイルサイズは一定ではなく、動的であるため、次のファイルを読み取っている間に変更されます。私はファイルサイズ(file.length)のストリームのサイズを増やそうとしましたが、それと同じ問題です。 –

+0

これがファイルの場合は、 'file.length()'を使ってファイルサイズを取得できます。実際、コードの元のバージョンはまさにそれを行いました。依然としてOOM例外が発生している場合は、ヒープがファイル全体を保持するのに十分な大きさになるまでヒープサイズを大きくする必要があります。 (代わりに、ファイルをメモリに保持する必要がないようにプログラムの残りの部分を変更してください...) –

1

whileループにエラーがあります。

while (bytesRead >= -1) { 
    writer.write(buffer, 0, bytesRead); 
    bytesRead = reader.read(buffer); 
} 

にそれを変更してもreaderを閉じることを忘れないでください。

(それはまだメモリの非常に大きな金額が必要になります。)

+0

私はこれもやっているが同じ問題を抱えている。 –

+0

これも '/'ではなく、元のコードはjvmがクラッシュするまで最初の1024バイトを出力する無限ループでした。デバッグのためには、ドキュメント全体をバイト配列に読み込んで渡すことができます(高速APIは、出力ストリームが受け入れられる場所のどこでも配列をサポートします)。それはあなたが渡されたストリームで高速apiがやっているかもしれないものに対して、バイト配列への文書の読み込みから問題を絞り込むことができます。 – sbaker

0

私はホスト上で十分な連続した仮想メモリを持っていないことで、Windowsの原因でC#で同様の問題を見てきました。 Windowsの場合は、VM領域を増やすことができます。

関連する問題