Bytebuffers と NIO を使用するときに OutOfMemoryError を回避するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/28675

質問

使っています ByteBuffers そして FileChannels バイナリデータをファイルに書き込みます。大きなファイルに対して、または複数のファイルに対してこれを連続して実行すると、 OutOfMemoryError 例外。私は他の場所でそれを使用していることを読みました Bytebuffers NIO は壊れているため、使用しないでください。すでにこの種の問題に直面し、大量のバイナリ データを Java のファイルに効率的に保存する解決策を見つけた人はいますか?

jvmオプションです -XX:MaxDirectMemorySize 進むべき道は?

役に立ちましたか?

解決

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

他のヒント

Java をチェックしてください マップされたバイトバッファ, 、「ダイレクトバッファ」とも呼ばれます。基本的に、このメカニズムは 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 パフォーマンスのヒント

ファイルにアクセスすると、 ランダムなファッション (ここを読んで、スキップして、そこに書いて、戻ってください) そうすると問題が発生します ;-)

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

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

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

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

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

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top