3

ByteBuffersおよびを使用しFileChannelsて、バイナリ データをファイルに書き込みます。大きなファイルに対して、または複数のファイルに対して連続してそれを行うと、OutOfMemoryError例外が発生します。BytebuffersNIO での使用は壊れており、避けるべきであることを他の場所で読みました。すでにこの種の問題に直面していて、大量のバイナリ データを Java のファイルに効率的に保存するための解決策を見つけた人はいますか?

jvm オプションを使用-XX:MaxDirectMemorySizeする方法はありますか?

4

6 に答える 6

7

一度にすべてのデータを含む巨大な ByteBuffer を作成しないでください。はるかに小さい ByteBuffer を作成し、データを入力してから、このデータを FileChannel に書き込みます。次に、ByteBuffer をリセットし、すべてのデータが書き込まれるまで続行します。

于 2008-08-26T17:26:45.953 に答える
5

「ダイレクト バッファ」とも呼ばれるJava のMapped Byte Buffersを確認してください。基本的に、このメカニズムは OS の仮想メモリ ページング システムを使用して、バッファをディスクに直接「マップ」します。OS は、ディスクやメモリとの間のバイトの移動を自動的に非常に迅速に管理するため、仮想マシンのオプションの変更について心配する必要はありません。これにより、奇妙なハックなしで、従来の Java ストリームベースの I/O よりも優れた NIO のパフォーマンスを利用することもできます。

私が考えることができる唯一の2つのキャッチは次のとおりです。

  1. 32 ビット システムでは、マップされたすべてのバイト バッファーの合計が4GB 弱に制限されます。(これは実際には私のアプリケーションの制限であり、現在は 64 ビット アーキテクチャで実行しています。)
  2. 実装は JVM 固有であり、要件ではありません。Sun の JVM を使用していますが、問題はありませんが、YMMV です。

Kirk Pepperdine (やや有名な Java パフォーマンスの第一人者) は、Web サイト (www.JavaPerformanceTuning.com) に関与しており、MBB の詳細がいくつか記載されています。NIO パフォーマンスのヒント

于 2008-08-26T18:01:52.420 に答える
1

ランダムな方法でファイルにアクセスする場合(ここを読み、スキップし、そこに書き、戻る)、問題が発生します;-)

ただし、大きなファイルのみを書き込む場合は、ストリームの使用を真剣に検討する必要があります。float、int、String、さらにはシリアライズ可能なオブジェクトを書き込むのに便利java.io.FileOutputStreamなように、バイトごとにファイルに書き込むか、他のストリーム (つまりDataOutputStream、 ) にラップするために直接使用できます。ObjectOutputStreamファイルを読み取るための同様のクラスが存在します。

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

于 2008-08-26T17:35:50.767 に答える
0

前の 2 つの回答は、かなり妥当に思えます。コマンド ライン スイッチが機能するかどうかは、メモリ使用量がどれだけ早く制限に達するかによって異なります。使用可能なメモリを少なくとも 3 倍にするのに十分な RAM と仮想メモリがない場合は、提示された代替案のいずれかを使用する必要があります。

于 2008-08-26T18:02:58.703 に答える
0

transferFromメソッドを使用すると、以前の回答でも指摘されているように、一度にではなく段階的にチャネルに書き込むと仮定すると、これに役立ちます。

于 2008-08-26T18:51:13.393 に答える
0

これは、特定の JDK ベンダーとバージョンに依存する場合があります。

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

JVM がユーザーに代わってダイレクト バッファーを作成している可能性があるため、自分でダイレクト バッファーを使用していない場合でも、これによりやけどを負う可能性があります。たとえば、非直接 ByteBuffer を SocketChannel に書き込むと、内部で直接バッファーが作成され、実際の I/O 操作に使用されます。

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

于 2008-09-26T15:14:51.200 に答える