java.nioのMappedByteBufferを使用してそれぞれ数GBのファイルを読み取る特定のバイナリ形式(興味がある場合はnfdump )のパーサークラスを作成しました。バイナリ形式は、一連のヘッダーとほとんどが固定サイズのバイナリレコードであり、nextRecord()を呼び出すことによって呼び出されたものにフィードされます。nextRecord()は、ステートマシンをプッシュし、完了するとnullを返します。それはうまく機能します。開発マシンで動作します。
私の本番ホストでは、数分または数時間実行できますが、常に「java.lang.InternalError:コンパイルされたJavaコードでの最近の安全でないメモリアクセス操作で障害が発生しました」をスローし、Map.getIntの1つを指しています。 、getShortメソッド、つまりマップの読み取り操作。
マップを設定する議論の余地のない(?)コードは次のとおりです。
/** Set up the map from the given filename and position */
protected void open() throws IOException {
// Set up buffer, is this all the flexibility we'll need?
channel = new FileInputStream(file).getChannel();
MappedByteBuffer map1 = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
map1.load(); // we want the whole thing, plus seems to reduce frequency of crashes?
map = map1;
// assumes the host writing the files is little-endian (x86), ought to be configurable
map.order(java.nio.ByteOrder.LITTLE_ENDIAN);
map.position(position);
}
次に、さまざまなmap.get *メソッドを使用して、ファイルの終わりに到達してマップを閉じる前に、shorts、ints、longs、およびその他のバイトシーケンスを読み取ります。
開発ホストで例外がスローされるのを見たことがありません。しかし、私の本番ホストと開発の違いの重要な点は、前者では、NFSを介してこれらのファイルのシーケンスを読み取っているということです(おそらく最終的には6〜8 TB、まだ成長しています)。私の開発マシンでは、ローカルでこれらのファイルの選択肢が少なくなっています(60GB)が、本番ホストで爆発した場合、通常は60GBのデータに到達するかなり前です。
両方のマシンはjava1.6.0_20-b02を実行していますが、本番ホストはDebian / lennyを実行していますが、開発ホストはUbuntu/karmicです。それが違いを生むとは思いません。どちらのマシンにも16GBのRAMが搭載されており、同じJavaヒープ設定で実行されています。
私のコードにバグがある場合、JVMには十分なバグがあり、適切な例外をスローしないと考えています。しかし、これは、NFSとmmapの間の相互作用による、特定のJVM実装のバグであり、公式に修正された6244515の再発である可能性があります。
私はすでに「load」呼び出しを追加して、MappedByteBufferにその内容をRAMにロードするように強制しようとしました。これは、私が行った1回のテスト実行でエラーを遅らせるように見えましたが、それを防ぐことはできませんでした。または、クラッシュする前に最も長くかかったのは偶然かもしれません!
これまで読んだことがあり、以前にjava.nioでこの種のことを行ったことがある場合、あなたの本能は何でしょうか?今のところ私のものはnioなしでそれを書き直すことです:)