欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

netty中的ByteBuf源碼詳解

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

一、背景簡(jiǎn)介

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

二、ByteBuf和ByteBuffer對(duì)比

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

ByteBuffer

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

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

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

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

ByteBuf

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

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

當(dāng)寫完N個(gè)字節(jié)數(shù)據(jù)后,讀指針仍然是0,因?yàn)檫€沒有開始進(jìn)行讀事件,寫指針向后移動(dòng)了N個(gè)字節(jié)的位置,如下:

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

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

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

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

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

三、源碼

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

我們?cè)谶@里看下netty擴(kuò)容相關(guān)源碼邏輯。

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

public abstract ByteBuf writeBytes(byte[] src);

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

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

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

        private void ensureWritable0(int minWritableBytes) {
         // 安全檢查,保證寫入之前是可訪問的
         //ensureAccessible();
?
         // 可寫,不必?cái)U(kuò)容
        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));
        }
?
        //達(dá)到臨界條件,開始執(zhí)行擴(kuò)容邏輯
        // 計(jì)算新的容量,實(shí)際上為當(dāng)前容量擴(kuò)容至2的冪次方大小(具體是多少需要進(jìn)行后續(xù)判斷和計(jì)算)
        int newCapacity = alloc().calculateNewCapacity(writerIndex + minWritableBytes, maxCapacity);
        // 擴(kuò)容后的容量
        capacity(newCapacity);
    }

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

來到其實(shí)現(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));
        }
        // 擴(kuò)容的閾值,4兆字節(jié)大小
        final int threshold = 1048576 * 4;
        if (minNewCapacity == threshold) {
            return threshold;
        }
       //如果計(jì)劃一共需要的內(nèi)存容量大小大于閾值,則需要和最大容量j進(jìn)行比較
        if (minNewCapacity > threshold) {
            int newCapacity = minNewCapacity / threshold * threshold;
            if (newCapacity + threshold > maxCapacity) {
                newCapacity = maxCapacity;
            } else {
                newCapacity += threshold;
            }
            return newCapacity;
        }
?
        //如果計(jì)劃一共需要的內(nèi)存容量大小小于閾值,則以64為基數(shù)進(jìn)行倍增
        int newCapacity = 64;
        while (newCapacity < minNewCapacity) {
            newCapacity <<= 1;
        }
        return Math.min(newCapacity, maxCapacity);
    }

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

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

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

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

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

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

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

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

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

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

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

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

相關(guān)文章

  • Lucene單值編碼壓縮算法源碼解析

    Lucene單值編碼壓縮算法源碼解析

    這篇文章主要為大家介紹了Lucene單值編碼壓縮算法源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • try-cache-finally讀取文件錯(cuò)誤try-with-resources使用方法

    try-cache-finally讀取文件錯(cuò)誤try-with-resources使用方法

    這篇文章主要為大家介紹了try-cache-finally讀取文件錯(cuò)誤try-with-resources使用方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • SpringMVC中請(qǐng)求參數(shù)的獲取方式

    SpringMVC中請(qǐng)求參數(shù)的獲取方式

    這篇文章主要為大家介紹了SpringMVC中請(qǐng)求參數(shù)的獲取方式,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • Java中使用Jedis操作Redis的示例代碼

    Java中使用Jedis操作Redis的示例代碼

    本篇文章主要介紹了Java中使用Jedis操作Redis的示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • SWT(JFace)體驗(yàn)之List演示匯總

    SWT(JFace)體驗(yàn)之List演示匯總

    SWT(JFace)體驗(yàn)之List演示代碼匯總
    2009-06-06
  • SpringBoot簡(jiǎn)單實(shí)現(xiàn)文件上傳

    SpringBoot簡(jiǎn)單實(shí)現(xiàn)文件上傳

    這篇文章主要介紹了SpringBoot簡(jiǎn)單實(shí)現(xiàn)文件上傳,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,感興趣的小伙伴可以參考一下
    2022-09-09
  • springcloud組件技術(shù)分享(推薦)

    springcloud組件技術(shù)分享(推薦)

    Spring Cloud 是一系列框架的有序集合,它利用 Spring Boot 的開發(fā)便利性簡(jiǎn)化了分布式系統(tǒng)的開發(fā),比如服務(wù)發(fā)現(xiàn)、服務(wù)網(wǎng)關(guān)、服務(wù)路由、鏈路追蹤等。這篇文章主要介紹了springcloud組件技術(shù)分享,需要的朋友可以參考下
    2020-10-10
  • springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹形結(jié)構(gòu)

    springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹形結(jié)構(gòu)

    這篇文章主要介紹了springboot?vue接口測(cè)試HutoolUtil?TreeUtil處理樹形結(jié)構(gòu),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-05-05
  • java快速排序和選擇排序?qū)崿F(xiàn)實(shí)例解析

    java快速排序和選擇排序?qū)崿F(xiàn)實(shí)例解析

    這篇文章主要為大家介紹了java快速排序和選擇排序?qū)崿F(xiàn)實(shí)例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • 詳解java構(gòu)建者模式Builder

    詳解java構(gòu)建者模式Builder

    這篇文章主要介紹了java構(gòu)建者模式Builder,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04

最新評(píng)論