2008-08-26 5 views
3

バイナリデータをファイルに書き込むためにByteBuffersFileChannelsを使用しています。大きなファイルやそれを複数のファイルに対して連続して実行すると、OutOfMemoryError例外が発生します。 NIOでBytebuffersを使用しているのは壊れているので、避けてください。あなたはすでにこの種の問題に直面しており、大量のバイナリデータをJavaのファイルに効率的に保存するソリューションを見つけましたか?BytebuffersとNIOを使用しているときにOutOfMemoryErrorを回避するにはどうすればよいですか?

jvmオプション-XX:MaxDirectMemorySizeは行きますか?

答えて

6

私は一度にすべてのデータを含む巨大なByteBufferを作成しないと言います。はるかに小さいByteBufferを作成し、データで埋めて、このデータをFileChannelに書き込みます。その後、ByteBufferをリセットし、すべてのデータが書き込まれるまで続行します。

1

あなたは、あなたが問題;-)

を持っている(ここでは読み飛ばし、そこに書き、裏に移動)ランダム内のファイルにアクセスしかし、あなただけの大きなファイルを書き込む場合、あなたは真剣にする必要がある場合ストリームの使用を検討してください。 java.io.FileOutputStreamは、浮動小数点数、int、文字列、またはシリアル化可能なオブジェクトの書き込みの便宜のために、バイトの後にファイルバイトを直接書き込むか、他のストリーム(つまりDataOutputStream、ObjectOutputStream)にラップするために直接使用できます。同様のクラスがファイルを読み込むために存在します。

ストリームは、(ほとんど)任意の小さなメモリの任意の大きなファイルを操作するのに便利です。大多数の場合、ファイルシステムにアクセスするための好ましい方法です。

4

JavaのMapped Byte Buffers(「ダイレクトバッファ」とも呼ばれます)を参照してください。基本的に、このメカニズムは、OSの仮想メモリページングシステムを使用して、バッファをディスクに直接マップします。 OSは、ディスクとメモリとの間のバイト移動を魔法のように、非常に迅速に管理し、仮想マシンオプションの変更について心配する必要はありません。これにより、NIOの伝統的なJavaストリームベースのI/Oに比べてNIOのパフォーマンスが向上し、奇妙なハッキングが発生することもありません。私は考えることができる

2つのだけキャッチがあります:32ビットシステムで

  1. 、あなたはすべてのマップされたバイトバッファのためのすぐ下に4ギガバイト合計に制限されています。 (これは実際には私のアプリケーションの限界ですが、今は64ビットアーキテクチャで動作しています)
  2. 実装はJVM固有であり、要件ではありません。私はSunのJVMを使用していますが、問題はありませんが、YMMVです。

カークペパーダイン(多少有名なJavaのパフォーマンスの第一人者)は、いくつかのより多くのMBBの詳細を持っているウェブサイト、www.JavaPerformanceTuning.com、に関与している:NIO Performance Tips

+0

マップされたすべてのバイトバッファ(私のアプリケーションまたはOS上のすべてのもの)に制限があることを指摘してくれてありがとうございます。私の場合、MappedByteBufferを周りのファイルに対して試しても私は愚かなOutOfMemoryExceptionを受け取ります1.6GB!しかし、なぜ?私の残りのスペースがどれだけ大きいかを調べるにはどうすればいいですか?助けて! – Zordid

+0

@ Zordid Ummm ... 'MappedByteBuffer'(マップされたキーです!)は一般に' OutOfMemoryException'を引き起こしません。何かが壊れています。私はここでStackOverflowの新しい質問を作成することをお勧めします...コードで!誰かがあなたを助けることができるようです。 –

0

は、前の2つの応答はかなり合理的なようです。コマンドラインスイッチが動作するかどうかは、メモリの使用量がどれくらい速く制限されるかによって決まります。利用可能なメモリと少なくとも3倍の仮想メモリが不足している場合は、指定されている代替提案の1つを使用する必要があります。

0

transferFromメソッドを使用すると、チャネルに徐々に書き込むと仮定すると、以前の回答も指摘しているように、すべてを一度に書き込むとは限りません。

0

これは、特定のJDKベンダーとバージョンによって異なる場合があります。

一部のSun JVMではGCにバグがあります。ダイレクトメモリの不足はメインヒープのGCをトリガしませんが、ダイレクトメモリはメインヒープのガベージダイレクトByteBuffersによって固定されます。主ヒープがほとんど空の場合、それらは多くの場合、長い間収集されません。

直接バッファを使用していない場合でも、JVMが直接バッファを作成している可能性があるため、この問題が発生する可能性があります。たとえば、直接的でないByteBufferをSocketChannelに書き込むと、実際のI/O操作に使用するためのカバーの下に直接バッファが作成されます。

回避策は、少数のダイレクトバッファを自分で使用し、再利用のためにそれらを保持しておくことです。

関連する問題