web-dev-qa-db-ja.com

成長するByteBuffer

PutX()呼び出しが容量を超過した場合に動的に成長するJava.nio.ByteBufferの実装を見たことがありますか?

このようにしたい理由は2つあります。

  1. どれだけのスペースが事前に必要かはわかりません。
  2. スペースを使い果たすたびに、新しいByteBuffer.allocate()を実行してから、一括put()を実行したくないのです。
40
Seth

非同期I/Oが機能するには、連続メモリが必要です。 Cでは配列の再割り当てを試みることができますが、Javaでは新しいメモリを割り当てる必要があります。ByteArrayOutputStreamに書き込み、準備ができたらByteBufferに変換できます欠点は、メモリをコピーしていることです。効率的なIOのキーの1つは、メモリがコピーされる回数を減らすことです。

35
brianegge

ByteBufferは、その設計コンセプトが特定の配列のviewであり、直接参照することもできるため、実際にはこのように機能することはできません。奇妙なことが起こらない限り、その配列をより大きな配列に交換することはできませんでした。

使用したいのはDataOutputです。最も便利な方法は、(プレリリース)Guavaライブラリを使用することです:

ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.write(someBytes);
out.writeInt(someInt);
// ...
return out.toByteArray();

ただし、ByteArrayOutputStreamからDataOutputStreamを手動で作成し、AssertionErrorsにチェーンすることで、誤ったIOExceptionを処理することもできます。

9

Mina IOBuffer https://mina.Apache.org/mina-project/userguide/ch8-iobuffer/ch8-iobuffer.html をご覧ください

ただし、必要以上に割り当てることをお勧めします。あまり心配しないでください。バッファーを割り当てる(特にダイレクトバッファー)場合、OSは仮想メモリーを提供しますが、実際に使用される場合にのみ物理メモリーを使用します。仮想メモリは非常に安価でなければなりません。

6
Peter Lawrey

別のオプションは、大きなバッファで直接メモリを使用することです。これは仮想メモリを消費しますが、使用する物理メモリだけを使用します(通常4Kのページ単位)

したがって、1 MBのバッファを割り当てると、1 MBの仮想メモリを消費しますが、実際に使用しているアプリケーションに物理ページを提供するのはOSだけです。

その効果は、アプリケーションが仮想メモリを大量に使用しているが、比較的少量の常駐メモリを使用していることです。

5
Peter Lawrey

Nettyの DynamicChannelBuffer を見る価値があるかもしれません。私が便利だと思うものは:

  • slice(int index, int length)
  • 符号なしの操作
  • ライターとリーダーの分離インデックス
4
anonymous

入力ストリームを使用してファイルからデータを受信し(非ブロッキングが必要な場合は別のスレッドで)、バイト配列として取得する機能を提供する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); 
    }
1
Full Stack

実際、自動拡張バッファーは、はるかに直感的に操作できます。再割り当てという贅沢なパフォーマンスに余裕があるなら、なぜそうしないのでしょう!?

Nettyの ByteBuf はまさにこれを提供します。彼らが撮影したようなものですJava.nioの-​​ ByteBuffer を使用して、エッジを削り取り、使いやすくしました。

さらに、それは 独立したnetty-buffer パッケージなので、使用するために完全なNettyスイートを含める必要はありません。

0
antak