最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

netty中的ByteBuf源碼詳解

 更新時間:2023年11月22日 08:58:26   作者:波波仔86  
這篇文章主要介紹了netty中的ByteBuf源碼詳解,ByteBuf,顧名思義,就是字節(jié)緩沖區(qū),是Netty中非常重要的一個組件,某些場景下性能不是太好,netty開發(fā)團隊重新設(shè)計了ByteBuf用以替代原生ByteBuffer,需要的朋友可以參考下

一、背景簡介

ByteBuf,顧名思義,就是字節(jié)緩沖區(qū),是Netty中非常重要的一個組件。熟悉jdk NIO的同學(xué)應(yīng)該知道ByteBuffer,正是因為jdk原生ByteBuffer使用比較復(fù)雜,某些場景下性能不是太好,netty開發(fā)團隊重新設(shè)計了ByteBuf用以替代原生ByteBuffer。

二、ByteBuf和ByteBuffer對比

下面用圖示來展示ByteBuf和ByteBuffer工作原理:

ByteBuffer

ByteBuffer依靠flip()來切換模式,在讀模式下調(diào)用flip()切換為寫模式,在寫模式下limit和capacity相等,position標(biāo)識當(dāng)前寫的位置。在寫模式下調(diào)用flip()切換為讀模式,在讀模式下position回到起始位置開始讀,limit回到position位置表示能讀到多少數(shù)據(jù),capacity不變表示緩存區(qū)容量大小。

capacity:在讀/寫模式下都是固定的,就是緩沖區(qū)容量大小。

position:讀/寫位置指針,表示當(dāng)前讀(寫)到什么位置。

limit:在寫模式下表示最多能寫入多少數(shù)據(jù),此時和capacity相同。在讀模式下表示最多能讀多少數(shù)據(jù),此時它的值等于緩存區(qū)中實際數(shù)據(jù)量的大小。

ByteBuf

ByteBuf主要是通過readerIndex和writerIndex兩個指針進行數(shù)據(jù)的讀和寫,整個ByteBuf被這兩個指針最多分成三個部分,分別是可丟棄部分,可讀部分和可寫部分

剛初始化的時候,整個緩沖區(qū)還沒有數(shù)據(jù),讀寫指針都指向0,所有的內(nèi)容都是可寫部分,此時還沒有可讀部分和可丟棄部分,如下:

當(dāng)寫完N個字節(jié)數(shù)據(jù)后,讀指針仍然是0,因為還沒有開始進行讀事件,寫指針向后移動了N個字節(jié)的位置,如下:

當(dāng)開始讀數(shù)據(jù)并且讀取M個字節(jié)數(shù)據(jù)之后(M<N)寫指針位置不變,讀指針后移動了M個字節(jié)的位置,如下:

當(dāng)可丟棄部分數(shù)據(jù)被清空之后,readerindex重新回到起始位置,writerindex的位置為writerindex的值減去之前的readerindex,也就是M,相關(guān)圖示如下:

調(diào)用clear之后,writerindex和readerinde全部復(fù)位為0。它不會清除緩沖區(qū)內(nèi)容(例如,用填充0),而只是清除兩個指針。

更改的讀寫指針的值,每個位置上原本的字節(jié)內(nèi)容并沒有發(fā)生改變,只是變成了可寫狀態(tài)而已。

另請注意,此操作的語義不同于Buffer.clear()。

三、源碼

明白了ByteBuf工作原理之后,ByteBuf相關(guān)的api就很好理解了,在此附上netty官方api文檔,以供參閱

我們在這里看下netty擴容相關(guān)源碼邏輯。

擴容肯定是在寫入數(shù)據(jù)的時候會由相關(guān)邏輯判斷,我們隨便進入一個寫入字節(jié)的api方法。

public abstract ByteBuf writeBytes(byte[] src);

進入到其抽象子類AbstractByteBuf中。

    @Override
    public ByteBuf writeBytes(byte[] src) {
        writeBytes(src, 0, src.length);
        return this;
    }
    @Override
    public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {
        ensureAccessible();
        ensureWritable(length);
        setBytes(writerIndex, src, srcIndex, length);
        writerIndex += length;
        return this;
    }

首先ensureAccessible進行安全校驗,每種嘗試訪問緩沖區(qū)內(nèi)容的方法都應(yīng)調(diào)用此方法,以檢查緩沖區(qū)是否已釋放。然后ensureWritable判斷是否可寫,擴容相關(guān)邏輯就在這里進行判斷,如果緩沖區(qū)可寫執(zhí)行setBytes進行數(shù)據(jù)寫入,然后writerindex向后移動length的位置,最后將ByteBuf對象進行返回。我們重點看ensureWritable。

    @Override
    public ByteBuf ensureWritable(int minWritableBytes) {
        if (minWritableBytes < 0) {
            throw new IllegalArgumentException(String.format(
                    "minWritableBytes: %d (expected: >= 0)", minWritableBytes));
        }
        ensureWritable0(minWritableBytes);
        return this;
    }

直接進入ensureWritable0(minWritableBytes)方法中,此時minWritableBytes就是我們計劃需要申請的內(nèi)存大小空間。

        private void ensureWritable0(int minWritableBytes) {
         // 安全檢查,保證寫入之前是可訪問的
         //ensureAccessible();
?
         // 可寫,不必擴容
        if (minWritableBytes <= writableBytes()) {
            return;
        }
?
        //下標(biāo)越界
        if (minWritableBytes > maxCapacity - writerIndex) {
            throw new IndexOutOfBoundsException(String.format(
                    "writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",
                    writerIndex, minWritableBytes, maxCapacity, this));
        }
?
        //達到臨界條件,開始執(zhí)行擴容邏輯
        // 計算新的容量,實際上為當(dāng)前容量擴容至2的冪次方大小(具體是多少需要進行后續(xù)判斷和計算)
        int newCapacity = alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity);
        // 擴容后的容量
        capacity(newCapacity);
    }

可以看到真正開辟內(nèi)存空間新容量邏輯處理的是 alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity)執(zhí)行的,進入到方法里面。

來到其實現(xiàn)類AbstractByteBufAllocator的calculateNewCapacity方法。

     @Override  
    public int calculateNewCapacity(int minNewCapacity, int maxCapacity) {
        if (minNewCapacity < 0) {
            throw new IllegalArgumentException("minNewCapacity: " + minNewCapacity + " (expectd: 0+)");
        }
        if (minNewCapacity > maxCapacity) {
            throw new IllegalArgumentException(String.format(
                    "minNewCapacity: %d (expected: not greater than maxCapacity(%d)",
                    minNewCapacity, maxCapacity));
        }
        // 擴容的閾值,4兆字節(jié)大小
        final int threshold = 1048576 * 4;
        if (minNewCapacity == threshold) {
            return threshold;
        }
       //如果計劃一共需要的內(nèi)存容量大小大于閾值,則需要和最大容量j進行比較
        if (minNewCapacity > threshold) {
            int newCapacity = minNewCapacity / threshold * threshold;
            if (newCapacity + threshold > maxCapacity) {
                newCapacity = maxCapacity;
            } else {
                newCapacity += threshold;
            }
            return newCapacity;
        }
?
        //如果計劃一共需要的內(nèi)存容量大小小于閾值,則以64為基數(shù)進行倍增
        int newCapacity = 64;
        while (newCapacity < minNewCapacity) {
            newCapacity <<= 1;
        }
        return Math.min(newCapacity, maxCapacity);
    }

minNewCapacity是我們計劃一共需要的內(nèi)存容量大小,maxCapacity是最大緩沖區(qū)容量大小。首先判斷minNewCapacity 是否小于零或者minNewCapacity 是否大于maxCapacity,滿足任一都拋出異常信息,然后判斷我們計劃一共需要的內(nèi)存容量大小minNewCapacity 是否等于了閾值4M:

①、如果等于了閾值,新容量大小就是閾值4M。

②、如果計劃一共需要的內(nèi)存容量大小大于閾值,則maxCapacity和minNewCapacity 相對于閾值的整數(shù)倍再加上一個閾值進行大小判斷,如果大于maxCapacity,則新容量最大就是maxCapacity,返回maxCapacity,如果小于maxCapacity,則相當(dāng)于按照閾值的2倍進行擴容。

③、如果計劃一共需要的內(nèi)存容量大小小于閾值,則以64為基數(shù)只要小于我們計劃需要的內(nèi)存容量大小,就2倍擴容,最后選取循環(huán)后的擴容值和最大值兩個值其中的較小者。

至此擴容就完成了,總結(jié)來說就是在擴容過程中有一個擴容需要容量的一個閾值4M,如果我們需要的內(nèi)存空間等于這個閾值,那么擴容后的容量就是閾值大小,如果我們需要的內(nèi)存容量大小大于閾值或者小于閾值,其擴容邏輯判斷和擴容后返回的容量大小是不同的。但是最終擴容后的容量大小總是2的冪次方大小并且不會比maxCapacity大。

四、ByteBuf主要的繼承關(guān)系

從內(nèi)存分配的角度看,ByteBuf可以分為兩類

(1)堆內(nèi)存(HeapByteBuf)字節(jié)緩沖區(qū):特點是內(nèi)存的分配和回收速度快,可以被JVM自動收回;缺點就是如果進行Socket的I/O讀寫,需要額外做一次內(nèi)存復(fù)制,將堆內(nèi)存對應(yīng)的緩沖區(qū)復(fù)制到內(nèi)核Chanenel中,性能會有一定程度的下降。

(2)直接內(nèi)存(DirectByteBuf) 字節(jié)緩沖區(qū):非堆內(nèi)存,它在堆外進行內(nèi)存分配,相比于堆內(nèi)存,它的分配和回收速度會慢一些,但是將它寫入或者從Socket Channel中讀取時,由于少了一次內(nèi)存復(fù)制,速度比堆內(nèi)存快。

正式因為各有利弊,所以Netty提供了多種ByteBuf供開發(fā)者使用,經(jīng)驗表明,ByteBuf的最佳實踐是在I/O通信線程的讀寫緩沖區(qū)使用DirectByteBuf,后端業(yè)務(wù)消息的編解碼模塊使用HeapByteBuf,這樣組合可以達到性能最優(yōu)。

從內(nèi)存回收角度看,ByteBuf也可以分為兩類:基于對象池的ByteBuf和普通ByteBuf。兩者的主要區(qū)別就是基于對象池的ByteBuf可以重用ByteBuf對象,它自己維護了一個內(nèi)存池,可以循環(huán)利用創(chuàng)建的ByteBuf,提升內(nèi)存的使用效率,降低由于高負載導(dǎo)致的頻繁GC。測試表名使用內(nèi)存池后的Netty在高負載、大并發(fā)的沖擊下內(nèi)存和GC更加平穩(wěn)。

到此這篇關(guān)于netty中的ByteBuf源碼詳解的文章就介紹到這了,更多相關(guān)netty中的ByteBuf內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

水城县| 石屏县| 舟山市| 岳普湖县| 南阳市| 乌兰浩特市| 准格尔旗| 城步| 怀仁县| 昌都县| 普安县| 新泰市| 秦皇岛市| 城固县| 太和县| 洛浦县| 浦县| 五家渠市| 章丘市| 绵阳市| 惠水县| 涞源县| 周口市| 罗山县| 阳曲县| 清涧县| 东方市| 株洲市| 大关县| 肃宁县| 广汉市| 北辰区| 隆德县| 荣成市| 屏山县| 呼玛县| 黔西县| 全椒县| 滦南县| 玉门市| 延长县|