PutX()呼び出しが容量を超過した場合に動的に成長するJava.nio.ByteBufferの実装を見たことがありますか?
このようにしたい理由は2つあります。
非同期I/Oが機能するには、連続メモリが必要です。 Cでは配列の再割り当てを試みることができますが、Javaでは新しいメモリを割り当てる必要があります。ByteArrayOutputStream
に書き込み、準備ができたらByteBuffer
に変換できます欠点は、メモリをコピーしていることです。効率的なIOのキーの1つは、メモリがコピーされる回数を減らすことです。
ByteBufferは、その設計コンセプトが特定の配列のviewであり、直接参照することもできるため、実際にはこのように機能することはできません。奇妙なことが起こらない限り、その配列をより大きな配列に交換することはできませんでした。
使用したいのはDataOutput
です。最も便利な方法は、(プレリリース)Guavaライブラリを使用することです:
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();
ただし、ByteArrayOutputStreamからDataOutputStreamを手動で作成し、AssertionErrorsにチェーンすることで、誤ったIOExceptionを処理することもできます。
Mina IOBuffer https://mina.Apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html をご覧ください
ただし、必要以上に割り当てることをお勧めします。あまり心配しないでください。バッファーを割り当てる(特にダイレクトバッファー)場合、OSは仮想メモリーを提供しますが、実際に使用される場合にのみ物理メモリーを使用します。仮想メモリは非常に安価でなければなりません。
別のオプションは、大きなバッファで直接メモリを使用することです。これは仮想メモリを消費しますが、使用する物理メモリだけを使用します(通常4Kのページ単位)
したがって、1 MBのバッファを割り当てると、1 MBの仮想メモリを消費しますが、実際に使用しているアプリケーションに物理ページを提供するのはOSだけです。
その効果は、アプリケーションが仮想メモリを大量に使用しているが、比較的少量の常駐メモリを使用していることです。
Nettyの DynamicChannelBuffer を見る価値があるかもしれません。私が便利だと思うものは:
slice(int index, int length)
入力ストリームを使用してファイルからデータを受信し(非ブロッキングが必要な場合は別のスレッドで)、バイト配列として取得する機能を提供するByteArrayOutstreamにバイトを読み込むことをお勧めします。回避策を追加しすぎない簡単な例を示します。
try (InputStream inputStream = Files.newInputStream(
Paths.get("filepath"), StandardOpenOption.READ)){
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byteRead = 0;
while(byteRead != -1){
byteRead = inputStream.read();
baos.write(byteRead);
}
ByteBuffer byteBuffer = ByteBuffer.allocate(baos.size())
byteBuffer.put(baos.toByteArray());
//. . . . use the buffer however you want
}catch(InvalidPathException pathException){
System.out.println("Path exception: " + pathException);
}
catch (IOException exception){
System.out.println("I/O exception: " + exception);
}
実際、自動拡張バッファーは、はるかに直感的に操作できます。再割り当てという贅沢なパフォーマンスに余裕があるなら、なぜそうしないのでしょう!?
Nettyの ByteBuf
はまさにこれを提供します。彼らが撮影したようなものですJava.nio
の- ByteBuffer
を使用して、エッジを削り取り、使いやすくしました。
さらに、それは 独立したnetty-buffer
パッケージなので、使用するために完全なNettyスイートを含める必要はありません。