のネッティーソースコード解析ByteBuf

のネッティーソースコード解析ByteBuf


基礎ByteBuf

Javaの仁王のバッファ

プロセスは、データ送信中に、私たちはしばしば、バッファを使用しています。
JavaのNIOでのJavaの7つの基本的なタイプに対応し、達成するために、7つのネイティブのバッファーを提供してくれます。一般的にはより多くのByteBufferを使用します。ときは本当に少し無力ネイティブバッファは、私たちの毎日の使用を満たすために、しかし、複雑なアプリケーションを実行することが、ネイティブ・バッファ以下の欠点があります。私達の使用のために、より使いやすいインターフェイスを提供するためネッティーその包装、。

  • 我々はバッファインスタンスを作成するためのバッファクラスを割り当て、対応するメソッドを呼び出すと、バッファの長さが固定され、動的に拡大または縮小することができないが、それは、指定された領域を割り当てます。我々はデータを書き込む場合は、配列境界エラーが起こるのだろうバッファの容量よりも大きくなります。
  • バッファ一箇所のみのフラグ属性の位置、我々はデータアクセス位置を処理するための位置を変更する方法を反転さや巻き戻しができ、それはエラーにつながる可能性が信じています。
  • バッファ緩衝液のみのアクセス、フリップ、リリース、記号、比較、バルク運動やその他の基本的な操作を提供し、私たちは高度な機能を使用するには、手動でパッケージを所有し、維持する必要があり、非常に不便使用。

作品ByteBuf

ByteBufはまた、バイト配列を介してデータにアクセスするためのバッファとして、出現パターンでのByteBuffer JDK NIO素子封止を重合しました。
ByteBufは、読み取りを支援し、readerIndex writerIndex 2つの位置ポインタ操作によってバッファを記述することです。
オブジェクトの初期化時間、及び0のwriterIndex readerIndex値後、リードなどと書き込み動作、及びreaderIndex writerIndexは増加するが、writerIndex readerIndexを超えないようにして、読み出し動作中、0 readerIndexとの間の空間であろうdiscardReadBytes方法のByteBufを呼び出し、廃棄として扱われ、コンパクトな操作のByteBuffer、バッファの圧縮に類似する空間のこの部分を、再利用するために解放することができます。空間へreaderIndex writerIndexは、ByteBufferの限界位置に対応する空間は、空間のWriterIndex容量を読み取ることができる、のByteBufferの容量限界に空間的等価物は、書き込むことを継続することができます。
writerIndex位置ポインタとreaderIndexを読み出して分離バッファの読み出し動作を簡素化し、書き込むために、位置ポインタを用いて調整する必要がないように、書き込み操作。
同様に、ByteBufパッケージの操作を読み書き、我々はバッファに書き込み動作するとき空き容量が不足している場合、ワードが書き込まれるが、残りの空き領域が、検証される必要がある、動的に拡張する能力を提供しますセクションの数は、書き込み可能なバイトの最大数よりも少ない、バッファを動的に、それがバッファを再作成し、新しく作成された前のバッファにデータをコピーし、展開します

基本的な機能ByteBuf

  • シーケンシャルリード
    前リード動作に、検証のために利用可能な第1のバッファスペース。読み取られるバイトの長さが0よりも小さい場合に読み出されるバイトのバイト長はIndexOutOfBoundsExceptionをスローし、書かれたの長さよりも大きい場合、はIllegalArgumentException例外がスローされます。GetBytesメソッドは、対応するサブクラスによって実装される抽象メソッドであり、同じではないチェックを通過した後、現在のreaderIndexから出発して、getBytesメソッドを呼び出すことにより、達成するために、異なるサブクラスに、DSTの目標長さにバイトのデータ長を読み出します。データの読み出しに成功した場合、readerIndexは、長さの増加に対応となります。
public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) {
    checkReadableBytes(length);
    getBytes(readerIndex, dst, dstIndex, length);
    readerIndex += length;
    return this;
}
protected final void checkReadableBytes(int minimumReadableBytes) {
    ensureAccessible();
    if (minimumReadableBytes < 0) {
        throw new IllegalArgumentException("minimumReadableBytes: " + minimumReadableBytes + " (expected: >= 0)");
    }
    if (readerIndex > writerIndex - minimumReadableBytes) {
        throw new IndexOutOfBoundsException(String.format(
                "readerIndex(%d) + length(%d) exceeds writerIndex(%d): %s",
                readerIndex, minimumReadableBytes, writerIndex, this));
    }
}
  • シーケンシャル書き込み
    動作がsrcIndex開始バイト配列からソースで読み取り、データをByteBufの長さの現在の長さに書き込まれます。
    書き込みの長さは、はIllegalArgumentException例外がスローされ、0未満である場合にアレイに書き込まれたバイトの開始番号は、検証する必要がある場合の試験を通して、ByteBuf書き込まれたバイトの現在の数より少なくてもよい書き込まれたバイト数。バッファに書き込まれたバイト数が、容量MAXCAPACITYの最大ダイナミック膨張よりも大きい場合、それがスローされます
    そうでない場合、彼らは動的な拡張によって書き込まれたバイト数を満たすために必要があるだろう、はIndexOutOfBoundsExceptionを。再膨張後の最初の容量によって算出CalculateNewCapacity、次いで、異なるサブクラスは異なる実装を持って、それはまた、抽象メソッド容量拡張メソッドの呼び出しです。
    • 容量拡張演算、第1のゲートバルブは、4Mが設けられて、新しいバッファとして閾値容量に等しい閾値を使用する能力を拡張したい場合、それは、4M、4M増分にステップとして、閾値よりも大きい場合延長期間であれば、最大膨張容量よりも大きな容量を拡張するために、それは最大容量MAXCAPACITY新しい容量を拡張することができます。乗算の結果の後に展開し、新たな容量のバッファの結果としての能力よりも大きくなるまで、それ以外の場合は、64の開始から倍増しました。
    • バッファとして新しい容量の長さの我々だけwriterIndex +値ならば、書き込み動作は、各時間後の容量拡張の必要性を実行したときの最初のステップを2倍にすることにより、容量を拡張し、するには、その後、再び、容量拡張プロセスは、メモリの複製が必要ですあまりにも多くのメモリレプリケーションのパフォーマンスの低下システムを引き起こす可能性があり、その理由が再び倍増している大臣は、第一の空間に比較的小さく、倍増し、運転廃棄物は、あまりにも多くのメモリをもたらすことはありませんが、メモリの成長特定の時間に、その後、倍加時間、それゆえ、我々は、しきい値に到達した後に長い段階のアプローチによって平滑な成長にしきい値を設定する必要があり、メモリの無駄になります。
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
    ensureWritable(length);
    setBytes(writerIndex, src, srcIndex, length);
    writerIndex += length;
    return this;
}
public ByteBuf ensureWritable(int minWritableBytes) {
    if (minWritableBytes < 0) {
        throw new IllegalArgumentException(String.format(
                "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
    }

    if (minWritableBytes <= writableBytes()) {
        return this;
    }

    if (minWritableBytes > maxCapacity - writerIndex) {
        throw new IndexOutOfBoundsException(String.format(
                "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
                writerIndex, minWritableBytes, maxCapacity, this));
    }

    // Normalize the current capacity to the power of 2.
    int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);

    // Adjust to the new capacity.
    capacity(newCapacity);
    return this;
}
private int calculateNewCapacity(int minNewCapacity) {
    final int maxCapacity = this.maxCapacity;
    final int threshold = 1048576 * 4; // 4 MiB page

    if (minNewCapacity == threshold) {
        return threshold;
    }

    // If over threshold, do not double but just increase by threshold.
    if (minNewCapacity > threshold) {
        int newCapacity = minNewCapacity / threshold * threshold;
        if (newCapacity > maxCapacity - threshold) {
            newCapacity = maxCapacity;
        } else {
            newCapacity += threshold;
        }
        return newCapacity;
    }

    // Not over threshold. Double up to 4 MiB, starting from 64.
    int newCapacity = 64;
    while (newCapacity < minNewCapacity) {
        newCapacity <<= 1;
    }

    return Math.min(newCapacity, maxCapacity);
}
//UnpooledHeapByteBuf的capacity实现
public ByteBuf capacity(int newCapacity) {
    ensureAccessible();
    if (newCapacity < 0 || newCapacity > maxCapacity()) {
        throw new IllegalArgumentException("newCapacity: " + newCapacity);
    }

    int oldCapacity = array.length;
    if (newCapacity > oldCapacity) {
        byte[] newArray = new byte[newCapacity];
        System.arraycopy(array, 0, newArray, 0, array.length);
        setArray(newArray);
    } else if (newCapacity < oldCapacity) {
        byte[] newArray = new byte[newCapacity];
        int readerIndex = readerIndex();
        if (readerIndex < newCapacity) {
            int writerIndex = writerIndex();
            if (writerIndex > newCapacity) {
                writerIndex(writerIndex = newCapacity);
            }
            System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
        } else {
            setIndex(newCapacity, newCapacity);
        }
        setArray(newArray);
    }
    return this;
}
  • クリア動作
    クリア動作及びwriterIndex readerIndexがちょうど0に設定され、記憶されたデータを変更されません。
public ByteBuf clear() {
    readerIndex = writerIndex = 0;
    return this;
}
  • インデックスの操作

    • 書き込み位置指標提供:主に境界条件、0以上でreaderIndex、newReaderIndexを設定したときwriterIndexより大きいチェックするため、writerIndex設け、newWriterIndex readerIndexが現在の容量よりも大きく、小さくなければなりません。あなたがチェックできない場合、それははIndexOutOfBoundsExceptionをスローしていました。
    • マークとリセット動作理由:readerIndexとwriterIndex、従ってmarkedReaderIndex又はmarkedWriterIndexマークまたは操作位置のインデックスを指定する必要がリセット、マーク操作は現在readerIndex又はwriterIndexが設定されます。リセット動作後、その値に対応する組み込みマークであります対応readerIndex()またはwriterIndex()を呼び出します。
  • バッファの再利用は、
    すでにdiscardReadByteバッファ法によって読み取られ、再利用に行くことができます。
    まずreaderIndex裁判官:
    • 0 readerIndexが等しい場合、それは、読み出しデータがないことを意味し、直接戻すために使用することができる空間的再利用はありません。
    • readerIndex writerIndexより大きい0に等しいとしない場合には、リードデータバッファがあることを示して廃棄され、バッファがまだ読み込まれていません。また、マークする必要があり、この方法は、readerIndexがwriterIndex元writerIndex-readerIndex、0である、setBytesがバイト配列、データが読み取られることはありませんが、バッファの先頭に移動させ、再びreaderIndex writerIndexを設定するためにコピーを呼び出しますそれをリセットします。
      • 次いでより小さい場合、最初、デクリメント単語よりmarkedReaderIndexが小さい場合、markedReaderIndexは減少とその後markedWriterIndex比較、0に設定され、デクリメントと比較し、次いでmarkedReaderIndexのバックアップを作成し、markedWriterIndexも0に設定され、そうでなければmarkedWriterIndex以下デクリメント。
      • 言葉の減少分よりも大きなmarkedReaderIndex場合、markedReaderIndexとmarkedReaderIndexは減少にそれを差し引い。
    • readerIndex等しいwriterIndex場合、それは何のバッファが存在しないことを示し、その上のマークの上に直接、再設定し、何もメモリコピーを再利用することはできません。
public ByteBuf discardReadBytes() {
    ensureAccessible();
    if (readerIndex == 0) {
        return this;
    }

    if (readerIndex != writerIndex) {
        setBytes(0, this, readerIndex, writerIndex - readerIndex);
        writerIndex -= readerIndex;
        adjustMarkers(readerIndex);
        readerIndex = 0;
    } else {
        adjustMarkers(readerIndex);
        writerIndex = readerIndex = 0;
    }
    return this;
}
protected final void adjustMarkers(int decrement) {
    int markedReaderIndex = this.markedReaderIndex;
    if (markedReaderIndex <= decrement) {
        this.markedReaderIndex = 0;
        int markedWriterIndex = this.markedWriterIndex;
        if (markedWriterIndex <= decrement) {
            this.markedWriterIndex = 0;
        } else {
            this.markedWriterIndex = markedWriterIndex - decrement;
        }
    } else {
        this.markedReaderIndex = markedReaderIndex - decrement;
        markedWriterIndex -= decrement;
    }
}
  • skipBytes

私たちはバイトの一部をスキップする必要があるときは、データをリードバックするバイトの長さを指定したメソッド呼び出しのskipBytesをスキップすることができます。
スキップの長さは、0未満、その後はIllegalArgumentExceptionがスローされ、現在のバッファ長をスキップするとはIndexOutOfBoundsExceptionを投げることができ、読み取りの長さよりも大きい場合は最初のジャンプの長さが決定されます。チェックが渡された場合、新しいreaderindex元readerIndex +長writerIndexより新しいreaderIndexが大きい場合、それははIndexOutOfBoundsExceptionがスローされます、またはreaderIndexを更新します。

public ByteBuf skipBytes(int length) {
    checkReadableBytes(length);
    int newReaderIndex = readerIndex + length;
    if (newReaderIndex > writerIndex) {
        throw new IndexOutOfBoundsException(String.format(
                "length: %d (expected: readerIndex(%d) + length <= writerIndex(%d))",
                length, readerIndex, writerIndex));
    }
    readerIndex = newReaderIndex;
    return this;
}

ソースコード解析ByteBuf

ByteBuf

AbstractReferenceCountedByteBuf

AbstractReferenceCountedByteBufが割り当てと破壊オブジェクトを追跡するために使用される参照カウントベースクラス、自動メモリ再生ByteBuf達成されます。

  • メンバ変数
    • refCntUpdater refCntUpdater AtomicIntegerFieldUpdaterタイプのメンバ変数であり、スレッドの安全性を達成するために、メンバ変数のアトミック更新操作することができます。
    • REFCNT_FIELD_OFFSET REFCNT_FIELD_OFFSETが、これはUnpooledDirectByteBuf PooledDirectByteBufと2つのサブクラスを相殺するために使用される、REFCNT AbstractReferenceCountedByteBufメモリ・アドレス・フィールドを識別しています。
    • REFCNT揮発性変数は、オブジェクト引用を追跡するために使用されるスレッドの視認性を確保するように修正されます
  • オブジェクト参照カウンタ
    参照カウンタを保持するすべてのメソッド呼び出しがインクリメントされます。スピン動作により基準カウンタの初期値を基準カウンタを追加する方法を保持する限り、プログラムが正しく実行されると、それはアプリケーションに回数が等しい最小値であると時間を解放すべきであるByteBuf対応しますこれは、再利用されます。数は、オブジェクトが誤って引用されたことを示し、0のときInteger型の最大値に等しい回数が、スローされた場合、IllegalReferenceCountExceptionは、例外をスロー
    IllegalReferenceCountException例外。この方法は、原子更新操作を維持するのcompareAndSet refCntUpdaterによって実行され、比較器は、変数を変更する他のスレッドが存在する場合、比較が失敗した場合のcompareAndSetは、取得した期待値を比較値を使用し、再度スピンし、そして再び参照カウンタの値を取得していますスピンを終了し、そうでなければ、それはプラスになり、比較してください。
    同様の剥離方法、この方法を保持するだけでなく、判断するスピンサイクルを更新するが、REFCNTの値は、アプリケーションが到達不能になっているオブジェクト参照としてリリースの数とカウンタを参照することを示す、1に等しいとき、オブジェクトがガーベッジであるべきですリサイクルコレクションが出て、DEALLOCATE呼び出すメソッドは、オブジェクトを解放しByteBuf
public ByteBuf retain() {
    for (;;) {
        int refCnt = this.refCnt;
        if (refCnt == 0) {
            throw new IllegalReferenceCountException(0, 1);
        }
        if (refCnt == Integer.MAX_VALUE) {
            throw new IllegalReferenceCountException(Integer.MAX_VALUE, 1);
        }
        if (refCntUpdater.compareAndSet(this, refCnt, refCnt + 1)) {
            break;
        }
    }
    return this;
}
    
public final boolean release() {
    for (;;) {
        int refCnt = this.refCnt;
        if (refCnt == 0) {
            throw new IllegalReferenceCountException(0, -1);
        }

        if (refCntUpdater.compareAndSet(this, refCnt, refCnt - 1)) {
            if (refCnt == 1) {
                deallocate();
                return true;
            }
            return false;
        }
    }
}

UnpooledHeapByteBuf

UnpooledHeapByteBufメモリが割り当てられ、または解除された場合には、各IOオペレーション、しばしば性能に影響を与えるUnpooledHeapByteBufオブジェクトを作成するために、ヒープメモリ割当バイトバッファを達成するために、非スレッドプールです。

  • メンバ変数
    • メモリ割り当てのためのByteBufAllocator
    • データのバイトを格納するバイト配列バッファとして配列
    • ByteBufferのは仁王のByteBufferを変換するために網状ByteBufを実装します
  • 動的に拡張バッファは、
    最初の新しい容量の大きさが最大スケーラブル容量MAXCAPACITYは、IllegalArgumentException例外未満0以上であれば、容量拡張を確認する必要があり、動的バッファの容量拡張メソッドの呼び出し。
    オリジナルよりも新しい拡張容量は、その後、新たに拡張され、容量の新しいバイト配列バッファ容量を作成する場合は、チェックを通過した後、その後行くために新しい配列に古いデータをコピーし、メモリコピーのためSystem.arraycopyのを呼び出しますその後はsetArray配列で置き換えます。オリジナルビューtmpNioBufferは、動的に広がった後に制御する必要があります。
    新しい現在のバッファ容量が容量よりも小さい場合、動的拡張が必要とされないが、必要ではサブバッファの一部としてデータを傍受します。
    • それは継続writerIndex newCapacityと比べてより小さい場合に最初の電流は、newCapacity readerIndex未満である、newCapacity writerIndexワードよりも大きい、それは、インデックスデータの更新が完了した後に現在の可読メモリにコピーすることによってnewCapacity writerIndex、それSystem.arraycopyのに設定される場合新しいバイト配列バッファへ。
    • newCapacity少ないreaderIndexよりは、それが新しい読めるバイト配列バッファにコピーされる新しいデータが存在しないことを示している場合、単にnewCapacityは最終的にはsetArray交換用のバイト配列を呼び出すことができますされている更新readerIndexでwriterIndexを置きます。
 public ByteBuf capacity(int newCapacity) {
    ensureAccessible();
    if (newCapacity < 0 || newCapacity > maxCapacity()) {
        throw new IllegalArgumentException("newCapacity: " + newCapacity);
    }

    int oldCapacity = array.length;
    if (newCapacity > oldCapacity) {
        byte[] newArray = new byte[newCapacity];
        System.arraycopy(array, 0, newArray, 0, array.length);
        setArray(newArray);
    } else if (newCapacity < oldCapacity) {
        byte[] newArray = new byte[newCapacity];
        int readerIndex = readerIndex();
        if (readerIndex < newCapacity) {
            int writerIndex = writerIndex();
            if (writerIndex > newCapacity) {
                writerIndex(writerIndex = newCapacity);
            }
            System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);
        } else {
            setIndex(newCapacity, newCapacity);
        }
        setArray(newArray);
    }
    return this;
}
  • setBytes
    コピーするバイトの配列は、データが第一有効性試験である、またはインデックスの値が0未満srcIndexある場合、IllegalArgumentExceptionがインデックス+容量値が+ srcIndex単語のsrc.lengthの値よりも大きい長さまたは長さの値よりも大きい場合にスローされます、はIndexOutOfBoundsExceptionがスローされます。チェックを通過した後、System.arraycopyのバイト配列の複製を呼び出します。
public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) {
    checkSrcIndex(index, length, srcIndex, src.length);
    System.arraycopy(src, srcIndex, array, index, length);
    return this;
}
protected final void checkSrcIndex(int index, int length, int srcIndex, int srcCapacity) {
    checkIndex(index, length);
    if (srcIndex < 0 || srcIndex > srcCapacity - length) {
        throw new IndexOutOfBoundsException(String.format(
                "srcIndex: %d, length: %d (expected: range(0, %d))", srcIndex, length, srcCapacity));
    }
}
  • 網状ByteBufと仁王のByteBuffer変換
    網状にByteBufは仁王のByteBuffer、ByteBufferのに変換のみnioBuffer方法で、ByteBufferの中に作成するために、対応するバイト配列を渡す必要も、スライスメソッドを呼び出し、静的メソッドをラップしていますあなたは、元のバッファの元のByteBufferバッファ開始位置の同時期から共有データ要素を作成することができます。バッファを再利用しないであろうnioBuffer方法はreaderIndexとwriterIndexの独立性を保証することができます。
public ByteBuffer nioBuffer(int index, int length) {
    ensureAccessible();
    return ByteBuffer.wrap(array, index, length).slice();
}

PooledByteBuf

メモリプール管理Netty4を添加した後、メモリプール管理を通じて大幅ByteBufの性能を作成するために以前より改善されています。

  • PoolChunk
    • メモリブロックの最小単位はページを割り当てるために使用することができます
    • のチャンクページコレクション

チャンクのメモリブロックの割り当ておよび解放を担うPoolChunkバイナリページのように構成され、デフォルトのページサイズは8K、チャンクサイズは2 ^ 11ページ、すなわち16Mは、バイナリ層11、底部を構成していますリーフノード8192の層は、ページ数として、各メモリの割り当ては簡単にメモリ操作の連続性を保証しなければなりません。メモリ領域内の各ノードは、ノードは、メモリ領域に割り当てられているを表す場合、そのノードが割り当てられたとして、ノードのメモリ要求のすべての子ノードが無視されますマークされ、そのオフセットアドレスを記録します。各メモリ割り当ては8K(2 ^ n)のメモリサイズは、第一の層Kの左側から見て開始され、利用可能なメモリ・セグメントを見つけるために、端CHUNKSIZE /(2 ^ k)に割り当てる必要があるメモリブロックのサイズであります使用可能なノード。

  • PoolArena

メモリ割り当てに、中央メモリの割り当てを管理し、メモリの割り当てを提供しつつ、解放および性能を解放するために、一般的にメモリの連続チャンクに予め割り当てられたであろう、メモリ動作は、頻繁に繰り返さ大きいことをする必要はありません連続したメモリブロックは、メモリアリーナと呼ばれ、PoolArenaネッティーメモリプールの実装クラスです。
網状において、PoolArenaチャンクは、複数で構成され、それぞれの複数のページがチャンクにより構成される。PoolArenaは共同チャンクとページと管理によって運営されています。

  • PoolSubpage

各ページが決定された第一のメモリ割り当て要求に応じてメモリブロックサイズのサイズであるメモリの等しいサイズのブロックへのメモリ割り当てのためのページ未満分割されている場合場合。あなたがなど、メモリブロックのサイズを適用するにしたいしたくない場合は、メモリブロックのサイズと同じだけ、メモリのメモリブロックの最初のメモリにページを割り当てることができ、唯一の新しいページにメモリ割り当てを適用することができます。
ストレージ・エリア・ページの使用は、各ビットが占有の一つの領域を表し、ビットマップを維持するために長い配列を介してです。

PooledDirectByteBuf

  • バイトのバッファを作成し
    、メモリプールの実装、作成するたびにバイトバッファは、新しい直接ではないので、しかし、メモリプールから取得し、その後、読み取りと参照カウンタを設定して、インデックスを作成し、バッファの最大容量に戻りました。
static PooledHeapByteBuf newInstance(int maxCapacity) {
    PooledHeapByteBuf buf = RECYCLER.get();
    buf.reuse(maxCapacity);
    return buf;
}
final void reuse(int maxCapacity) {
    maxCapacity(maxCapacity);
    setRefCnt(1);
    setIndex0(0, 0);
    discardMarks();
}
  • 例には、バイト・バッファ・コピー
    のコピー方法は、独立して、元のバッファの、バイトバッファのインスタンスをコピーすることができます。
    これは、最初のインデックスと長さの合法性を決定し、新しいバッファを割り当てるdirectBuffer PooledByteBufAllocatorメソッドを呼び出す必要があります。異なるサブクラスが異なる実装を持っているためnewDirectBuffer方法は、抽象メソッドです。その後、unpooled場合、それは直接、新しいバッファを作成することがプールされている場合、それはメモリプールから使用可能な次のバッファを取得します。
public ByteBuf copy(int index, int length) {
    checkIndex(index, length);
    ByteBuf copy = alloc().directBuffer(length, maxCapacity());
    copy.writeBytes(this, index, length);
    return copy;
}
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
    if (initialCapacity == 0 && maxCapacity == 0) {
        return emptyBuf;
    }
    validate(initialCapacity, maxCapacity);
    return newDirectBuffer(initialCapacity, maxCapacity);
}
// PooledByteBufAllocator 
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
    PoolThreadCache cache = threadCache.get();
    PoolArena<ByteBuffer> directArena = cache.directArena;

    ByteBuf buf;
    if (directArena != null) {
        buf = directArena.allocate(cache, initialCapacity, maxCapacity);
    } else {
        if (PlatformDependent.hasUnsafe()) {
            buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
        } else {
            buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
        }
    }

    return toLeakAwareBuffer(buf);
}
//UnpooledByteBufAllocator
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
    ByteBuf buf;
    if (PlatformDependent.hasUnsafe()) {
        buf = new UnpooledUnsafeDirectByteBuf(this, initialCapacity, maxCapacity);
    } else {
        buf = new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);
    }

    return toLeakAwareBuffer(buf);
}

ヘルパークラス分析ByteBuf

ByteBufHolder

ByteBufHolderは異なるプロトコル、データフォーマット及びフィールド異なるプロトコルメッセージを使用してデータ伝送があることByteBufする同じなので、抽象ByteBufHolderしない含む場合、それはより容易に、データByteBufがアクセスできるコンテナByteBufありますパッケージは、異なる実装を持っている別のサブクラスは、ユーザーが自分のニーズに応じて実装することができます。ネッティーは、デフォルトの実装のDefaultByteBufHolderを提供します。

ByteBufAllocator

ByteBufAllocator異なる実装網状バイトバッファに係るバイトバッファディスペンサは、二つの異なるディスペンサーPooledByteBufAllocatorとUnpooledByteBufAllocatorに分割されています。彼らはByteBufの異なる割り当て方法を提供します。

CompositeByteBuf

CompositeByteBufが仮想バッファであり、それは複数ByteBuf ByteBuf図に組み立てることができます。
JavaのNIOでは、我々は達成するために二つの方法があります

  • ByteBuffer ByteBufferのに追加のデータをコピーし、またはに新しく作成されたByteBufferに新しいのByteBuffer、ByteBufferの他のコピーを再作成します。
  • 一緒に複数のByteBuffer、一元管理および保守することによりコンテナ保管。

でネッティーでは、CompositeByByteBufは、コンポーネントの種類のコレクションを維持しました。コンポーネントはByteBufラッパークラスは、重合ByteBufれる。メンテナンス位置ずれ量を収集情報。通常の状況下で、我々はCompositeByteBufオブジェクトをインスタンス化するためにコンストラクタによって直接CompositeByteBufを作成するのではなく、するByteBufAllocator.compositeBuffer()とUnpooled.wrappedBuffer(ByteBuf ...)メソッドを使用する必要があります。

private int addComponent0(int cIndex, ByteBuf buffer) {
    checkComponentIndex(cIndex);
    if (buffer == null) {
        throw new NullPointerException("buffer");
    }

    int readableBytes = buffer.readableBytes();

    // No need to consolidate - just add a component to the list.
    Component c = new Component(buffer.order(ByteOrder.BIG_ENDIAN).slice());
    if (cIndex == components.size()) {
        components.add(c);
        if (cIndex == 0) {
            c.endOffset = readableBytes;
        } else {
            Component prev = components.get(cIndex - 1);
            c.offset = prev.endOffset;
            c.endOffset = c.offset + readableBytes;
        }
    } else {
        components.add(cIndex, c);
        if (readableBytes != 0) {
            updateComponentOffsets(cIndex);
        }
    }
    return cIndex;
}
private void consolidateIfNeeded() {
    final int numComponents = components.size();
    if (numComponents > maxNumComponents) {
        final int capacity = components.get(numComponents - 1).endOffset;
    
        ByteBuf consolidated = allocBuffer(capacity);
    
        for (int i = 0; i < numComponents; i ++) {
            Component c = components.get(i);
            ByteBuf b = c.buf;
            consolidated.writeBytes(b);
            c.freeIfNecessary();
        }
        Component c = new Component(consolidated);
        c.endOffset = c.length;
        components.clear();
        components.add(c);
    }
}

public CompositeByteBuf removeComponent(int cIndex) {
    checkComponentIndex(cIndex);
    Component comp = components.remove(cIndex);
    comp.freeIfNecessary();
    if (comp.length > 0) {
        updateComponentOffsets(cIndex);
    }
    return this;
}

private static final class Component {
    final ByteBuf buf;
    final int length;
    int offset;
    int endOffset;

    Component(ByteBuf buf) {
        this.buf = buf;
        length = buf.readableBytes();
    }

    void freeIfNecessary() {
        buf.release(); // We should not get a NPE here. If so, it must be a bug.
    }
}

ByteBufUtil

ByteBufUtilはByteBufを操作する静的メソッドの一連を提供するユーティリティクラス、ByteBufあります。

おすすめ

転載: blog.csdn.net/qq_34730511/article/details/80568062
おすすめ