netty UnpooledHeapByteBuf 源碼分析

來源:互聯網
上載者:User

標籤:擴容   orm   完成   protect   buffer   needed   影響   def   released   

UnpooledHeapByteBuf 是基於堆記憶體進行記憶體配置的位元組緩衝區,沒有基於對象池技術實現,這意味著每次I/O的讀寫都會建立一個新的UnpooledHeapByteBuf,頻繁進行大塊記憶體的分配和回收對效能會造成一定的影響,但是對比與堆外記憶體的申請和釋放,它的成本會低一些。

相對與PooledHeapByteBuf,UnpooledHeapByteBuf 的實現原理更加簡單,也不容易出現記憶體管理方面的問題,在滿足效能的情況下,盡量使用UnpooledHeapByteBuf 。

1.成員變數
private final ByteBufAllocator alloc;//彙總一個ByteBufAllocator,用於UnpooledHeapByteBuf的記憶體配置private byte[] array;//byte 數組作為緩衝區private ByteBuffer tmpNioBuf;//用於實現Netty ByteBuf 到 JDK ByteBuffer 的轉換

事實上,如果使用JDK 的ByteBuffer替換byte數組也是可行的 ,直接使用byte數組的根本原因是提升效能和更加便捷的進行位操作。JDK 的ByteBuffer底層實現也是byte數組,如下。

public abstract class ByteBuffer    extends Buffer    implements Comparable<ByteBuffer>{    // These fields are declared here rather than in Heap-X-Buffer in order to    // reduce the number of virtual method invocations needed to access these    // values, which is especially costly when coding small buffers.    //    final byte[] hb;                  // Non-null only for heap buffers    final int offset;    boolean isReadOnly;                 // Valid only for heap buffers
2.動態擴充緩衝區
@Overridepublic 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;}
/** * Should be called by every method that tries to access the buffers content to check * if the buffer was released before. */protected final void ensureAccessible() {    if (refCnt() == 0) {        throw new IllegalReferenceCountException(0);    }}

方法 的入口首先對新容量進行合法性校正,如果大於容量上限或者小於0,則拋出IllegalArgumentException異常。

判斷新的容量值是否大於當前的緩衝區容量,如果大於則需要動態擴充,通過 byte[] newArray = new byte[newCapacity];建立新的緩衝區位元組數組,然後通過 System.arraycopy進行記憶體複製,將舊的位元組數組複製到新建立的位元組數組中,最後調用setArray(newArray);替換舊的位元組數組。

private void setArray(byte[] initialArray) {    array = initialArray;    tmpNioBuf = null;}

動態擴容完成後,需要將原來的視圖tmpNioBuf設定為空白。

如果新的容量小於當前緩衝區容量不需要動態擴充,但是需要截取當前緩衝區建立一個新的子緩衝區。先判斷下讀索引是否小於新的容量值,如果小於進一步判斷寫索引是否大於新的容量值,如果大於則將寫索引設定為新的容量值(防止越界)。更新完寫索引之後,通過 System.arraycopy將當前可讀的位元組數組複製到新建立的子緩衝區中, System.arraycopy(array, readerIndex, newArray, readerIndex, writerIndex - readerIndex);

如果新的容量值小於讀索引,說明沒有可讀的位元組數組需要複製到新建立的緩衝區中,將讀寫索引為新的容量值即可。最後調用setArray方法替換原來的位元組數組。

3.位元組數組複製
@Overridepublic 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));    }}

校正index,length的值,如果小於0,拋出IllegalArgumentException異常,然後對兩者之和進行判斷,如果大於緩衝區的容量,則拋出IndexOutOfBoundsException異常。srcIndex和srcCapacity,與之類似。校正通過之後,調用 System.arraycopy(src, srcIndex, array, index, length)方法進行位元組數組的複製。

protected final void checkIndex(int index, int fieldLength) {    ensureAccessible();    if (fieldLength < 0) {        throw new IllegalArgumentException("length: " + fieldLength + " (expected: >= 0)");    }    if (index < 0 || index > capacity() - fieldLength) {        throw new IndexOutOfBoundsException(String.format(                "index: %d, length: %d (expected: range(0, %d))", index, fieldLength, capacity()));    }}

注意: ButeBuf以set和get開頭讀寫緩衝區的方法不會修改讀寫索引。

4.轉換為JDK ByteBuffer

ByteBuffer 是基於byte數組實現,NIO的ByteBuffer提供wrap方法,可以將byte數群組轉換成ByteBuffer對象。

/**     * Wraps a byte array into a buffer.     *     * <p> The new buffer will be backed by the given byte array;     * that is, modifications to the buffer will cause the array to be modified     * and vice versa.  The new buffer‘s capacity will be     * <tt>array.length</tt>, its position will be <tt>offset</tt>, its limit     * will be <tt>offset + length</tt>, and its mark will be undefined.  Its     * {@link #array backing array} will be the given array, and     * its {@link #arrayOffset array offset} will be zero.  </p>     *     * @param  array     *         The array that will back the new buffer     *     * @param  offset     *         The offset of the subarray to be used; must be non-negative and     *         no larger than <tt>array.length</tt>.  The new buffer‘s position     *         will be set to this value.     *     * @param  length     *         The length of the subarray to be used;     *         must be non-negative and no larger than     *         <tt>array.length - offset</tt>.     *         The new buffer‘s limit will be set to <tt>offset + length</tt>.     *     * @return  The new byte buffer     *     * @throws  IndexOutOfBoundsException     *          If the preconditions on the <tt>offset</tt> and <tt>length</tt>     *          parameters do not hold     */    public static ByteBuffer wrap(byte[] array,                                    int offset, int length)    {        try {            return new HeapByteBuffer(array, offset, length);        } catch (IllegalArgumentException x) {            throw new IndexOutOfBoundsException();        }    }

UnpooledHeapByteBuf.java

@Overridepublic ByteBuffer nioBuffer(int index, int length) {    ensureAccessible();    return ByteBuffer.wrap(array, index, length).slice();}

調用了ByteBuffer的slice方法,由於每次調用nioBuffer都會建立一個新的ByteBuffer,因此此處的slice方法起不到重用緩衝區的效果,只能保證讀寫索引的獨立性。

5.與子類相關的方法

isDirect方法:如果基礎堆記憶體實現的ByteBuf,返回false,

@Overridepublic boolean isDirect() {    return false;}

hasArray方法:因為UnpooledHeapByteBuf是基於位元組數組實現,返回true

@Overridepublic boolean hasArray() {    return true;}

array方法:因為UnpooledHeapByteBuf是基於位元組數組實現,所以傳回值是內部的位元組數群組成員變數。調用array方法之前,可以先使用hasArray方法進行判斷,如果返回false說明當前ByteBuf不支援array方法。

@Overridepublic byte[] array() {    ensureAccessible();    return array;}

 

netty UnpooledHeapByteBuf 源碼分析

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.