netty(十三)初識(shí)Netty - ByteBuf 拷貝 及 簡(jiǎn)要總結(jié)

Netty基于不同的使用場(chǎng)景,提供了幾個(gè)ByteBuf當(dāng)中零拷貝的方法。這些方法和我們?cè)贜IO當(dāng)中談到的不同领虹,在NIO當(dāng)中的零拷貝最終是為了減少用戶態(tài)和內(nèi)核態(tài)之間的數(shù)據(jù)拷貝。

本章節(jié)我們針對(duì)Netty提供的幾個(gè)方法進(jìn)行簡(jiǎn)單學(xué)習(xí)和使用求豫。

一塌衰、零拷貝

先聲明一點(diǎn),如果要使用以下方法的話蝠嘉,可能要配合前面文章介紹的retain()方法去增加引用計(jì)數(shù)最疆,否則原ByteBuf被release()后,則會(huì)導(dǎo)致我們拷貝出來(lái)的buf使用失敗蚤告,導(dǎo)致異常努酸。

1.1 slice

“零拷貝”的體現(xiàn)之一,對(duì)原始 ByteBuf 進(jìn)行切片杜恰,切分成多個(gè) ByteBuf蚊逢,切片后的 ByteBuf 并沒(méi)有發(fā)生內(nèi)存復(fù)制,只是多了引用到分片后的Bytebuf箫章,然而還是使用的原始 ByteBuf 的內(nèi)存烙荷,切片后的 ByteBuf 維護(hù)獨(dú)立的 read,write 指針檬寂,修改子分片终抽,會(huì)修改原ByteBuf。

示例代碼:

    public static void main(String[] args) {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);
        byteBuf.writeBytes(new byte[]{1,2,3,4,5,6,7,8,9,0});

        printBuf(byteBuf);

        //分片1
        ByteBuf slice1 = byteBuf.slice(0, 5);
        printBuf(slice1);

        //分片2
        ByteBuf slice2 = byteBuf.slice(5, 5);
        printBuf(slice2);

        //將最后一位0修改成10
        slice2.setByte(4,10);
        printBuf(slice2);

        //打印修改后的byteBuf
        printBuf(byteBuf);

    }

    static void printBuf(ByteBuf byteBuf){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i< byteBuf.writerIndex();i++) {
            stringBuilder.append(byteBuf.getByte(i));
        }
        System.out.println(stringBuilder);
    }

結(jié)果:

1234567890
12345
67890
678910
12345678910

注意:slice后的分片桶至,不能再次寫入新的數(shù)據(jù)昼伴,這回影響原ByteBuf。

1.2镣屹、duplicate

“零拷貝”的體現(xiàn)之一圃郊,拷貝了原始 ByteBuf 所有內(nèi)容,長(zhǎng)度仍然以byteBuf為準(zhǔn)女蜈,不能寫入新數(shù)據(jù)持舆,也是與原始 ByteBuf 使用同一塊底層內(nèi)存,只是讀寫指針是獨(dú)立的伪窖。

使用示例:

public class DuplicateTest {

    public static void main(String[] args) {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);
        byteBuf.writeBytes(new byte[]{1,2,3,4,5,6,7,8,9,0});

        //拷貝一塊buf
        ByteBuf duplicate = byteBuf.duplicate();
        printBuf(duplicate);

        //將最后一位0修改成10逸寓,看一下byteBuf
        duplicate.setByte(9,10);
        printBuf(byteBuf);

        // 寫入新數(shù)據(jù)11,看byteBuf
        duplicate.writeByte(11);
        printBuf(byteBuf);
    }

    static void printBuf(ByteBuf byteBuf){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i< byteBuf.writerIndex();i++) {
            stringBuilder.append(byteBuf.getByte(i));
        }
        System.out.println(stringBuilder);
    }
}

1.3 CompositeByteBuf

“零拷貝”的體現(xiàn)之一覆山,可以將多個(gè) ByteBuf 合并為一個(gè)邏輯上的 ByteBuf竹伸,避免拷貝。

public class CompositeByteBufTest {

    public static void main(String[] args) {
        ByteBuf byteBuf1 = ByteBufAllocator.DEFAULT.buffer(5);
        byteBuf1.writeBytes(new byte[]{1, 2, 3, 4, 5});

        ByteBuf byteBuf2 = ByteBufAllocator.DEFAULT.buffer(5);
        byteBuf2.writeBytes(new byte[]{6, 7, 8, 9, 0});

        CompositeByteBuf compositeByteBuf = ByteBufAllocator.DEFAULT.compositeBuffer();
        // 組合兩個(gè)byteBuf簇宽,主要要使用帶有increaseWriteIndex的勋篓,否則會(huì)失敗吧享。
        compositeByteBuf.addComponents(true,byteBuf1, byteBuf2);

        printBuf(compositeByteBuf);
    }

    static void printBuf(ByteBuf byteBuf){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i< byteBuf.writerIndex();i++) {
            stringBuilder.append(byteBuf.getByte(i));
        }
        System.out.println(stringBuilder);
    }
}

1.4 Unpooled

Unpooled 是一個(gè)工具類,提供了非池化的 ByteBuf 創(chuàng)建譬嚣、組合耙蔑、復(fù)制等操作。

這里僅介紹其跟“零拷貝”相關(guān)的 wrappedBuffer 方法

使用示例:

    public static void main(String[] args) {
        ByteBuf byteBuf1 = ByteBufAllocator.DEFAULT.buffer(5);
        byteBuf1.writeBytes(new byte[]{1, 2, 3, 4, 5});

        ByteBuf byteBuf2 = ByteBufAllocator.DEFAULT.buffer(5);
        byteBuf2.writeBytes(new byte[]{6, 7, 8, 9, 0});

//        CompositeByteBuf compositeByteBuf = ByteBufAllocator.DEFAULT.compositeBuffer();
//        // 組合兩個(gè)byteBuf孤荣,主要要使用帶有increaseWriteIndex的甸陌,否則會(huì)失敗。
//        compositeByteBuf.addComponents(true,byteBuf1, byteBuf2);

        // 組合兩個(gè)byteBuf盐股,底層使用CompositeByteBuf钱豁。
        ByteBuf wrappedBuffer = Unpooled.wrappedBuffer(byteBuf1, byteBuf2);

        printBuf(wrappedBuffer);
    }

    static void printBuf(ByteBuf byteBuf){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i< byteBuf.writerIndex();i++) {
            stringBuilder.append(byteBuf.getByte(i));
        }
        System.out.println(stringBuilder);
    }

二、深度拷貝

ByteBuf提供了copy方法疯汁,這一類方法是真正的拷貝原ByteBuf到新的內(nèi)存牲尺,返回一個(gè)新的ByteBuf,與原ByteBuf沒(méi)有關(guān)系幌蚊。

提供兩個(gè)拷貝谤碳,一個(gè)是全量;一個(gè)指定位置和長(zhǎng)度溢豆。

public abstract ByteBuf copy();

public abstract ByteBuf copy(int index, int length);

使用示例:

public class CopyTest {

    public static void main(String[] args) {
        ByteBuf byteBuf = ByteBufAllocator.DEFAULT.buffer(10);
        byteBuf.writeBytes(new byte[]{1,2,3,4,5,6,7,8,9,0});

        ByteBuf copy1 = byteBuf.copy();
        printBuf(copy1);

        ByteBuf copy2 = byteBuf.copy(5, 5);
        printBuf(copy2);
    }

    static void printBuf(ByteBuf byteBuf){
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i< byteBuf.writerIndex();i++) {
            stringBuilder.append(byteBuf.getByte(i));
        }
        System.out.println(stringBuilder);
    }
}

關(guān)于Bytebuf的入門就介紹這么多了蜒简,后面會(huì)深入去探討更細(xì)節(jié)的內(nèi)容。

Bytebuf簡(jiǎn)單總結(jié)

  • 池化 - 可以重用池中 ByteBuf 實(shí)例漩仙,更節(jié)約內(nèi)存搓茬,減少內(nèi)存溢出的可能
  • 讀寫指針?lè)蛛x,不需要像 ByteBuffer 一樣切換讀寫模式
  • 可以自動(dòng)擴(kuò)容
  • 支持鏈?zhǔn)秸{(diào)用队他,使用更流暢
  • 很多地方體現(xiàn)零拷貝卷仑,例如 slice、duplicate麸折、CompositeByteBuf
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锡凝,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子垢啼,更是在濱河造成了極大的恐慌窜锯,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膊夹,死亡現(xiàn)場(chǎng)離奇詭異衬浑,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)放刨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)尸饺,“玉大人进统,你說(shuō)我怎么就攤上這事助币。” “怎么了螟碎?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵眉菱,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我掉分,道長(zhǎng)俭缓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任酥郭,我火速辦了婚禮华坦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘不从。我一直安慰自己惜姐,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布椿息。 她就那樣靜靜地躺著歹袁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寝优。 梳的紋絲不亂的頭發(fā)上条舔,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音乏矾,去河邊找鬼逞刷。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妻熊,可吹牛的內(nèi)容都是我干的夸浅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼扔役,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼帆喇!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起亿胸,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤坯钦,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后侈玄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體婉刀,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年序仙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了突颊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖律秃,靈堂內(nèi)的尸體忽然破棺而出爬橡,到底是詐尸還是另有隱情,我是刑警寧澤棒动,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布糙申,位于F島的核電站,受9級(jí)特大地震影響船惨,放射性物質(zhì)發(fā)生泄漏柜裸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一粱锐、第九天 我趴在偏房一處隱蔽的房頂上張望疙挺。 院中可真熱鬧,春花似錦卜范、人聲如沸衔统。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)锦爵。三九已至,卻和暖如春奥裸,著一層夾襖步出監(jiān)牢的瞬間险掀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工湾宙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留樟氢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓侠鳄,卻偏偏與公主長(zhǎng)得像埠啃,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伟恶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容