深入研究Netty框架之ByteBuf類繼承結構

ByteBuf類繼承關係圖如下:

ReferenceCounted:對象引用計數器,初始化ReferenceCounted對象時,引用數量refCnt爲1,調用retain()可增加refCnt,release()用於減少refCnt。refCnt爲1時,說明對象實際不可達,release()方法將立即調用deallocate()釋放對象。如果refCnt爲0,說明對象被錯誤的引用。在AbstractReferenceCountedByteBuf源碼分析小節將詳細介紹ReferenceCounted的原理。

ByteBuf:實現接口ReferenceCounted和Comparable,實現ReferenceCounted使得ByteBuf具備引用計數的能力,方便跟蹤ByteBuf對象分配和釋放。

  • ByteBuf直接子類

EmptyByteBuf:用於構建空ByteBuf對象,capacity和maxCapacity均爲0。

ReplayingDecoderBuffer:用於構建在IO阻塞條件下實現無阻塞解碼的特殊ByteBuf對象,當要讀取的數據還未接收完全時,拋出異常,交由ReplayingDecoder處理。

SwappedByteBuf:用於構建具有切換字節順序功能的ByteBuf對象,默認ByteBuf對象使用BIG_ENDIAN(大字節序)存儲數據,SwappedByteBuf可以在BIG_ENDIAN和LITTLE_ENDIAN之間自由切換。TCP/IP各層協議均採用網絡字節序(BIG_ENDIAN),關於字節序的更多內容不詳細介紹。

WrappedByteBuf:用於裝飾ByteBuf對象,主要有AdvancedLeakAwareByteBuf、SimpleLeakAwareByteBuf和UnreleasableByteBuf三個子類。這裏WrappedByteBuf使用裝飾者模式裝飾ByteBuf對象,AdvancedLeakAwareByteBuf用於對所有操作記錄堆棧信息,方便監控內存泄漏;SimpleLeakAwareByteBuf只記錄order(ByteOrder endianness)的堆棧信息;UnreleasableByteBuf用於阻止修改對象引用計數器refCnt的值。

AbstractByteBuf:提供ByteBuf的默認實現,同時組合ResourceLeakDetector和SwappedByteBuf的能力,ResourceLeakDetector是內存泄漏檢測工具,SwappedByteBuf用於字節序不同時轉換字節序。

  • AbstractByteBuf直接子類

AbstractDerivedByteBuf:提供派生ByteBuf的默認實現,主要有DuplicatedByteBuf、ReadOnlyByteBuf和SlicedByteBuf。

DuplicatedByteBuf使用裝飾者模式創建ByteBuf的複製對象,使得複製後的對象與原對象共享緩衝區的內容,但是獨立維護自己的readerIndex和writerIndex。部分源碼如下:

    private final ByteBuf buffer;

    public DuplicatedByteBuf(ByteBuf buffer) {
        super(buffer.maxCapacity());
        //共享緩衝區內容
        if (buffer instanceof DuplicatedByteBuf) {
            this.buffer = ((DuplicatedByteBuf) buffer).buffer;
        } else {
            this.buffer = buffer;
        }
        //調用自身的setIndex方法維護readerIndex和writerIndex
        setIndex(buffer.readerIndex(), buffer.writerIndex());
    }
    //所有操作都是通過調用被裝飾對象buffer的相應方法實現
    @Override
    public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) {
        buffer.getBytes(index, dst, dstIndex, length);
        return this;
    }
    @Override
    public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) {
        buffer.getBytes(index, dst, dstIndex, length);
        return this;
    }

ReadOnlyByteBuf使用裝飾者模式創建ByteBuf的只讀對象,該只讀對象與原對象共享緩衝區的內容,但是獨立維護自己的readerIndex和writerIndex,之後所有的寫操作都被限制;部分源碼如下:

    private final ByteBuf buffer;

    public ReadOnlyByteBuf(ByteBuf buffer) {
        super(buffer.maxCapacity());

        if (buffer instanceof ReadOnlyByteBuf || buffer instanceof DuplicatedByteBuf) {
            this.buffer = buffer.unwrap();
        } else {
            this.buffer = buffer;
        }
        setIndex(buffer.readerIndex(), buffer.writerIndex());
    }
    @Override
    protected void _setLong(int index, long value) {
        throw new ReadOnlyBufferException();
    }

    @Override
    public int setBytes(int index, InputStream in, int length) {
        throw new ReadOnlyBufferException();
    }

SlicedByteBuf使用裝飾者模式創建ByteBuf的一個子區域ByteBuf對象,返回的ByteBuf對象與當前ByteBuf對象共享緩衝區的內容,但是維護自己獨立的readerIndex和writerIndex,允許寫操作。

AbstractReferenceCountedByteBuf:提供修改對象引用計數器相關操作的默認實現。

  • AbstractReferenceCountedByteBuf直接子類

CompositeByteBuf:用於將多個ByteBuf組合在一起,形成一個虛擬的ByteBuf對象,支持讀寫和動態擴展。內部使用List<Component>組合多個ByteBuf。推薦使用ByteBufAllocator的compositeBuffer()方法,Unpooled的工廠方法compositeBuffer()或wrappedBuffer(ByteBuf... buffers)創建CompositeByteBuf對象。

FixedCompositeByteBuf:用於將多個ByteBuf組合在一起,形成一個虛擬的只讀ByteBuf對象,不允許寫入和動態擴展。內部使用Object[]將多個ByteBuf組合在一起,一旦FixedCompositeByteBuf對象構建完成,則不會被更改。

PooledByteBuf<T>:基於內存池的ByteBuf,主要爲了重用ByteBuf對象,提升內存的使用效率;適用於高負載,高併發的應用中。主要有PooledDirectByteBuf,PooledHeapByteBuf,PooledUnsafeDirectByteBuf三個子類,PooledDirectByteBuf是在堆外進行內存分配的內存池ByteBuf,PooledHeapByteBuf是基於堆內存分配內存池ByteBuf,PooledUnsafeDirectByteBuf也是在堆外進行內存分配的內存池ByteBuf,區別在於PooledUnsafeDirectByteBuf內部使用基於PlatformDependent相關操作實現ByteBuf,具有平臺相關性。

ReadOnlyByteBufferBuf:只讀ByteBuf,內部持有ByteBuffer對象,相關操作委託給ByteBuffer實現,該ByteBuf限內部使用,ReadOnlyByteBufferBuf還有一個子類ReadOnlyUnsafeDirectByteBuf。

UnpooledDirectByteBuf:在堆外進行內存分配的非內存池ByteBuf,內部持有ByteBuffer對象,相關操作委託給ByteBuffer實現。

UnpooledHeapByteBuf:基於堆內存分配非內存池ByteBuf,即內部持有byte數組。

UnpooledUnsafeDirectByteBuf:與UnpooledDirectByteBuf相同,區別在於UnpooledUnsafeDirectByteBuf內部使用基於PlatformDependent相關操作實現ByteBuf,具有平臺相關性。

到此,ByteBuf繼承家族的各個成員對應的相關功能已介紹完成。

總結:

從內存分配角度看,ByteBuf主要分爲兩類:

  • 堆內存(HeapByteBuf)字節緩衝區:特點是內存的分配和回收速度快,可以被JVM自動回收;缺點是進行Socket的I/O讀寫需要額外進行一次內存複製,即將內存對應的緩衝區複製到內核Channel中,性能會有一定程度下降。
  • 直接內存(DirectByteBuf)字節緩衝區:在堆外進行內存分配,相比堆內存,分配和回收速度稍慢。但用於Socket的I/O讀寫時,少一次內存複製,速度比堆內存字節緩衝區快。

經驗表明,在I/O通信線程的讀寫緩衝區使用DirectByteBuf,後端業務消息的編解碼模塊使用HeapByteBuf,這樣組合可以達到性能最優。

從內存回收角度看,ByteBuf也分爲兩類:

  • 基於內存池的ByteBuf:優點是可以重用ByteBuf對象,通過自己維護一個內存池,可以循環利用創建的ByteBuf,提升內存的使用效率,降低由於高負載導致的頻繁GC。適用於高負載,高併發的應用中。推薦使用基於內存池的ByteBuf。
  • 非內存池的ByteBuf:優點是管理和維護相對簡單。

本節重點介紹ByteBuf繼承家族的各個成員,詳細功能後續將通過源碼講解,下一節介紹AbstractByteBuf源碼。

歡迎指出本文有誤的地方,轉載請註明原文出處https://my.oschina.net/7001/blog/743240

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章