摘要:使用來(lái)優(yōu)化套接字操作,盡可能消除由的緩沖區(qū)實(shí)現(xiàn)所導(dǎo)致的性能以及內(nèi)存使用率的懲罰,這種優(yōu)化發(fā)生在的核心代碼中,不會(huì)被暴露出來(lái)。當(dāng)前將會(huì)被增加所寫(xiě)入的字節(jié)數(shù)。
ByteBuf是Java NIO ByteBuffer的替代品,是網(wǎng)絡(luò)數(shù)據(jù)基本單位字節(jié)的容器。
ByteBuf的APINetty的數(shù)據(jù)處理API通過(guò)兩個(gè)組件暴漏:抽象類(lèi)ByteBuf和接口ByteBufHolder
ByteBuf優(yōu)點(diǎn):
他可以被用戶自定義的緩沖區(qū)類(lèi)型擴(kuò)展
通過(guò)內(nèi)置的復(fù)合緩沖區(qū)類(lèi)型實(shí)現(xiàn)了透明的零拷貝
容量可以按需增長(zhǎng)
在讀寫(xiě)兩種模式之間切換不需要調(diào)用ByteBuffer的flip()方法
讀寫(xiě)使用不同的索引
支持方法的鏈?zhǔn)秸{(diào)用
支持引用計(jì)數(shù)
支持池化
ByteBuf——數(shù)據(jù)容器 工作原理?ByteBuf維護(hù)兩個(gè)索引:一個(gè)用于讀取,一個(gè)用于寫(xiě)入。當(dāng)你從ByteBuf讀取時(shí),readIndex會(huì)被遞增已經(jīng)被讀取的字節(jié)數(shù),同樣的,當(dāng)向ByteBuf中寫(xiě)入數(shù)據(jù)時(shí),writeIndex也會(huì)被遞增。
如果readIndex和writeIndex處于同樣的位置,再次嘗試讀取數(shù)據(jù)將會(huì)觸發(fā)IndexOutOfBoundsException
名稱以read或者write開(kāi)頭的ByteBuf方法,將會(huì)推進(jìn)其對(duì)應(yīng)的索引,而名稱以set或者get開(kāi)頭的操作則不會(huì)。
名稱以set或者get開(kāi)頭的方法會(huì)有一個(gè)索引位置參數(shù),將會(huì)在該索引位置上進(jìn)行set或get操作
ByteBuf可以指定最大容量。如果寫(xiě)索引超過(guò)這個(gè)值會(huì)觸發(fā)異常IllegalArgumentException。默認(rèn)的最大值是Integer.MAX_VALUE
ByteBuf使用模式 堆緩沖區(qū)?將數(shù)據(jù)存儲(chǔ)在JVM的對(duì)空間中,這種模式又被成為支撐數(shù)組。它能在沒(méi)有使用池化的情況下提供快速的分配和釋放。
當(dāng)hasArray方法返回false時(shí),嘗試訪問(wèn)支撐數(shù)組將觸發(fā)UnsupportedOperationException異常。
直接緩沖區(qū)?NIO引入的ByteBuffer類(lèi)允許JVM實(shí)現(xiàn)通過(guò)本地調(diào)用來(lái)分配內(nèi)存,這樣可以避免在每次調(diào)用本地I/O操作之前(或者之后)將緩沖區(qū)的內(nèi)容復(fù)制到一個(gè)中間緩沖區(qū)(或者從中間緩沖區(qū)把內(nèi)容復(fù)制到緩沖區(qū))。
?直接緩沖區(qū)的主要特點(diǎn)是,分配和釋放都比較昂貴。
復(fù)合緩沖區(qū)?它為多個(gè)ByteBuf提供了一個(gè)聚合視圖??梢愿鶕?jù)需要添加或者刪除ByteBuf實(shí)例。Netty通過(guò)CompositeByteBuf(ByteBuf的子類(lèi))實(shí)現(xiàn)這個(gè)模式,它提供了一個(gè)將多個(gè)緩沖區(qū)表示為單個(gè)合并緩沖區(qū)的虛擬表示。
CompositeByteBuf中的ByteBuf實(shí)例可能同時(shí)包含直接內(nèi)存分配和非直接內(nèi)存分配。如果只有一個(gè)ByteBuf實(shí)例,那么CompositeByteBuf上的hasArray方法將返回該ByteBuf上的hasArray方法的值,否則將返回false。
?CompositeByteBuf不支持訪問(wèn)支撐數(shù)組,因此訪問(wèn)CompositeByteBuf中的數(shù)據(jù)類(lèi)似于訪問(wèn)直接緩沖區(qū)的模式。
?Netty使用CompositeByteBuf來(lái)優(yōu)化套接字I/O操作,盡可能消除由JDK的緩沖區(qū)實(shí)現(xiàn)所導(dǎo)致的性能以及內(nèi)存使用率的懲罰,這種優(yōu)化發(fā)生在Netty的核心代碼中,不會(huì)被暴露出來(lái)。
字節(jié)級(jí)操作 隨機(jī)訪問(wèn)索引?ByteBuf的索引是從0開(kāi)始:第一個(gè)字節(jié)的索引就是0,最后一個(gè)字節(jié)的索引是capacity() - 1。
如果方法中有一個(gè)索引值參數(shù),通過(guò)該方法訪問(wèn)數(shù)據(jù)既不會(huì)改變r(jià)eadIndex也不會(huì)改變writeIndex。
如果有需要,可以通過(guò)調(diào)用readIndex(index)或者writeIndex(index)手動(dòng)移動(dòng)兩者。
順序訪問(wèn)索引ByteBuf內(nèi)部分段示意圖如下:
可丟棄字節(jié)?在上圖中可丟棄字節(jié)指的就是已被讀取過(guò)的字節(jié),通過(guò)調(diào)用discardReadBytes()方法,可以丟棄它們并回收空間。可丟棄字節(jié)分段的初始大小為0,即readIndex,該值會(huì)隨著read操作的執(zhí)行而增加(get*操作不會(huì)移動(dòng)readIndex)。
discardReadBytes()方法只是移動(dòng)了可以讀取的字節(jié)以及writeIndex,而沒(méi)有對(duì)所有可寫(xiě)入的字節(jié)進(jìn)行擦除寫(xiě)。
discardReadBytes()會(huì)導(dǎo)致內(nèi)存復(fù)制,因?yàn)榭勺x字節(jié)必須要移動(dòng)到緩沖區(qū)開(kāi)始的位置。
可讀字節(jié)?可讀字節(jié)分段存儲(chǔ)了實(shí)際數(shù)據(jù)。新分配的、包裝的或者復(fù)制的緩沖區(qū)的默認(rèn)readINdex值為0。任何名稱以read或者skip開(kāi)頭的操作都將檢索或者跳過(guò)位于當(dāng)前readIndex的數(shù)據(jù),并將它增加已讀字節(jié)數(shù)。
如果被調(diào)用的方法需要一個(gè)ByteBuf參數(shù)作為寫(xiě)入的目標(biāo),并且沒(méi)有指定目標(biāo)索引參數(shù),那么該寫(xiě)入的目標(biāo)的writeIndex也將被增加。
可寫(xiě)字節(jié)?可以字節(jié)分段是指一個(gè)擁有未定義內(nèi)容的、寫(xiě)入就緒的內(nèi)存區(qū)域。新分配的緩沖區(qū)的writeIndex的默認(rèn)值為0。任何以write開(kāi)頭的方法都將從當(dāng)前的writeIndex開(kāi)始寫(xiě)數(shù)據(jù),并將它增加已經(jīng)寫(xiě)入的字節(jié)數(shù)。如果寫(xiě)操作的目標(biāo)也是ByteBuf,并且沒(méi)有指定源索引的值,則源緩沖區(qū)的readerIndex也會(huì)被增加相同的大小。
索引管理? JDK的InputStream定義了mark(int readLimit)和reset()方法,這些方法分別被用來(lái)將流中的當(dāng)前位置標(biāo)記為指定的值,以及將流重置到該位置。
?在ByteBuf中,可以調(diào)用markReadIndex()、markWriteIndex()、resetReaderIndex()、resetWriterIndex()來(lái)標(biāo)記和重置ByteBuf的readIndex和writeIndex,不過(guò)在ByteBuf中沒(méi)有readLimit參數(shù)指定標(biāo)記啥時(shí)候失效。
?在ByteBuf中,也可以通過(guò)調(diào)用readerIndex(int)或者writeIndex(int)來(lái)將索引移動(dòng)到指定位置。
?在ByteBuf中,可以通過(guò)clear()方法將readerIndex和writeIndex都設(shè)置為0,但是不會(huì)清楚內(nèi)存中的內(nèi)容。調(diào)用clear()方法比調(diào)用discardReadBytes()更加輕量,因?yàn)閏lear只是重置索引,不會(huì)復(fù)制任何的內(nèi)存。
查找操作?最簡(jiǎn)單的確定值的索引的方法是indexOf()。較復(fù)雜的查找可以通過(guò)一個(gè)ByteProcessor(Netty4.1版本以上,舊的版本采用ByteBufProcessor)參數(shù)達(dá)成。
派生緩沖區(qū)?派生緩沖區(qū)為ByteBuf提供了以專門(mén)的方式來(lái)呈現(xiàn)其內(nèi)容的視圖,這類(lèi)視圖的創(chuàng)建方式主要有以下幾種:
duplicate()
slice()
slice(int, int)
Unpooled.unmodifiableBuffer(...)
order(ByteOrder)
readSlice(int)
以上方法都會(huì)返回一個(gè)新的ByteBuf實(shí)例,它具有自己的讀索引、寫(xiě)索引和標(biāo)記索引。它會(huì)和源實(shí)例共享內(nèi)存,因此創(chuàng)建成本低廉,但是如果修改它的內(nèi)容,也就意味著修改了對(duì)應(yīng)的源實(shí)例。
如果需要一個(gè)現(xiàn)有緩沖區(qū)的真實(shí)副本,需要使用copy()或者copy(int,int)方法
讀/寫(xiě)操作讀寫(xiě)操作主要分為兩類(lèi):
get()和set()操作,從給定的索引開(kāi)始,并且保持索引不變
read()和write()操作,從給定的索引開(kāi)始,并且會(huì)根據(jù)已經(jīng)訪問(wèn)過(guò)的字節(jié)數(shù)對(duì)索引進(jìn)行調(diào)整。
方法名稱 | 描述 |
---|---|
getBoolean(int) | 返回給定索引處的Boolean值 |
getByte(int) | 返回給定索引處的字節(jié) |
getUnsignedByte(int) | 將給定索引處的無(wú)符號(hào)字節(jié)值作為short返回 |
getMedium(int) | 返回給定索引處的24位的中等int值 |
getUnsignedMedium(int) | 返回給定索引處的無(wú)符號(hào)的24位的中等int值 |
getInt(int) | 返回給定索引處的int值 |
getUnsignedInt(int) | 將給定索引處的無(wú)符號(hào)int值作為long返回 |
getLong(int) | 返回給定索引處long值 |
getShort(int) | 返回給定索引處的short值 |
getUnsignedShort(int) | 將給定索引處的無(wú)符號(hào)short值作為int返回 |
getByte(int, ...) | 將該緩沖區(qū)中從給定索引開(kāi)始的數(shù)據(jù)傳送到指定的目的地 |
方法名稱 | 描述 |
---|---|
setBoolean(int, boolean) | 設(shè)定給定索引處的Boolean值 |
setByte(int index, int value) | 設(shè)定給定索引處的字節(jié)值 |
setMedium(int index, int value) | 設(shè)定給定索引處的24位的中等int值 |
setInt(int index, int value) | 設(shè)定給定索引處的int值 |
setLong(int index, long value) | 設(shè)定給定索引處的long值 |
setShort(int index, int value) | 設(shè)定給定索引處的short值 |
方法名稱 | 描述 |
---|---|
readBoolean() | 返回當(dāng)前readIndex處的Boolean值,并將readIndex增加1 |
readByte() | 返回當(dāng)前readIndex處的字節(jié),并將readIndex增加1 |
readUnsignedByte() | 將當(dāng)前readIndex處的無(wú)符號(hào)字節(jié)值作為short返回,并將readIndex增加1 |
readMedium() | 返回當(dāng)前readIndex處的24位的中等int值,并將readIndex增加3 |
readUnsignedMedium() | 返回當(dāng)前readIndex處的24位的無(wú)符號(hào)的中等int值,并將readIndex增加3 |
readInt() | 返回當(dāng)前readIndex處的int值,并將readIndex增加4 |
readUnsignedMedium() | 返回當(dāng)前readIndex處的24位的無(wú)符號(hào)的中等int值,并將readerIndex增加3 |
readInt() | 返回當(dāng)前readIndex處的int值,并將readerIndex增加4 |
readUnsignedInt() | 將當(dāng)前readerIndex處的無(wú)符號(hào)的int值作為long值返回,并將readIndex增加4 |
readLong() | 返回當(dāng)前readIndex處的long值,并將readIndex增加8 |
readShort() | 返回當(dāng)前readIndex處的short值,并將readIndex增加2 |
readUnsignedShort() | 將當(dāng)前readIndex處的無(wú)符號(hào)short值作為int值返回,并將readIndex增加2 |
readBytes(ByteBuf byte[] destination, int dstIndex, [, int length]) | 將當(dāng)前ByteBuf中從當(dāng)前readIndex處開(kāi)始的(如果設(shè)置了,length長(zhǎng)度的字節(jié))數(shù)據(jù)傳送到一個(gè)目標(biāo)ByteBuf或者byte[],從目標(biāo)的dstIndex開(kāi)始的位置。本地的readIndex將被增加已經(jīng)傳輸?shù)淖止?jié)數(shù)。 |
方法 | 描述 |
---|---|
writeBoolean(boolean) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)boolean值,并將writeIndex增加1 |
writByte(byte) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)字節(jié)值,并將writeIndex增加1 |
writeMedium(int) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)中等的int值,并將writeIndex增加3 |
writeInt(int) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)int值,并將writeIndex增加4 |
writeLong(long) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)long值,并將writeIndex增加8 |
writeShort(int) | 在當(dāng)前writeIndex處寫(xiě)入一個(gè)short值,并將writeIndex增加2 |
writeBytes(source ByteBuf byte[] [,int srcIndex,int length]) | 從當(dāng)前writeIndex開(kāi)始,傳輸來(lái)自于指定源(ByteBuf或者byte[])的數(shù)據(jù)。如果提供了srcIndex和length,則從srcIndex開(kāi)始讀取,并且處理長(zhǎng)度為length的字節(jié)。當(dāng)前writeIndex將會(huì)被增加所寫(xiě)入的字節(jié)數(shù)。 |
方法 | 描述 |
---|---|
isReadable() | 如果至少有一個(gè)字節(jié)可供讀取,則返回true |
isWritable() | 如果至少有一個(gè)字節(jié)可被寫(xiě)入,則返回true |
readableBytes() | 返回可被讀取的字節(jié)數(shù) |
writableBytes() | 返回可被寫(xiě)入的字節(jié)數(shù) |
capacity() | 返回ByteBuf可容納的字節(jié)數(shù)。在此之后,它會(huì)嘗試再次擴(kuò)展直到達(dá)到maxCapacity() |
maxCapacity() | 返回ByteBuf可以容納的最大字節(jié)數(shù) |
hasArray() | 如果ByteBuf由一個(gè)字節(jié)數(shù)組支撐,則返回true |
array() | 如果ByteBuf由一個(gè)字節(jié)數(shù)組支撐則返回該數(shù)組;否則,它將拋出一個(gè)UnsupportedOperationException異常 |
?ByteBufHolder為Netty的高級(jí)特性提供了支持,如緩沖區(qū)池化,其中可以從池中借用ByteBuf,并且在需要時(shí)自動(dòng)釋放。
名稱 | 描述 |
---|---|
content() | 返回由這個(gè)ByteBufHolder所持有的ByteBuf |
copy() | 返回這個(gè)ByteBufHolder的一個(gè)深拷貝,包括一個(gè)其所包含的ByteBuf的非共享拷貝 |
duplicate() | 返回這個(gè)ByteBufHolder的一個(gè)淺拷貝,包括一個(gè)其所包含的ByteBuf的共享拷貝 |
?為了降低分配和釋放內(nèi)存的開(kāi)銷(xiāo),Netty通過(guò)ByteBufAllactor接口實(shí)現(xiàn)了(ByteBuf的)池化,它可以用來(lái)分配我們所描述過(guò)的任意類(lèi)型的ByteBuf實(shí)例。
名稱 | 描述 |
---|---|
buffer() buffer(int initialCapacity) buffer(int initialCapacity, int maxCapacity) |
返回一個(gè)基于堆或者直接內(nèi)存存儲(chǔ)的ByteBuf |
heapBuffer() heapBuffer(int initialCapacity) heapBuffer(int initialCapacity, int maxCapacity) |
返回一個(gè)基于堆內(nèi)存存儲(chǔ)的ByteBuf |
directBuffer() directBuffer(int initialCapacity) directBuffer(int initialCapacity, int maxCapacity) |
返回一個(gè)基于直接內(nèi)存存儲(chǔ)的ByteBuf |
compositeBuffer() compositeBuffer(int maxNumComponents) compositeDirectBuffer() compositeDirectBuffer(int maxNumComponents) compositeHeapBuffer() compositeHeapBuffer(int maxNumComponents) |
返回一個(gè)可以通過(guò)添加最大到指定數(shù)目的基于堆的或者直接內(nèi)存存儲(chǔ)的緩沖區(qū)來(lái)擴(kuò)展的CompositeByteBuf |
ioBuffer() | 返回一個(gè)用于套接字的I/O操作的ByteBuf |
Netty提供了兩種ByteBufAllocator的實(shí)現(xiàn):PooledByteBufAllocator和ByteBufAllocator。前者池化了ByteBuf的實(shí)例以提高性能并最大限度的減少內(nèi)存碎片,后者的實(shí)現(xiàn)不池化ByteBuf實(shí)例,并且每次被調(diào)用時(shí)都會(huì)返回一個(gè)新的實(shí)例。
Netty4.1以后默認(rèn)使用PooledByteBufAllocator
Unpooled緩沖區(qū)?Netty提供了一個(gè)簡(jiǎn)單的成為Unpooled的工具類(lèi),它提供了靜態(tài)的輔助方法來(lái)創(chuàng)建未池化的ByteBuf實(shí)例。
方法 | 描述 |
---|---|
buffer() buffer(int initialCapacity) buffer(int initialCapacity, int maxCapacity) |
返回一個(gè)未池化的基于堆內(nèi)存存儲(chǔ)的ByteBuf |
directBuffer() directBuffer(int initialCapacity) directBuffer(int initialCapacity, int maxCapacity) |
返回一個(gè)未池化的基于直接內(nèi)存存儲(chǔ)的ByteBUf |
wrappedBuffer() | 返回了一個(gè)包裝了給定數(shù)據(jù)的ByteBuf |
copiedBuffer() | 返回了一個(gè)復(fù)制了給定數(shù)據(jù)的ByteBuf |
?ByteBufUtil提供了用于操作ByteBuf的靜態(tài)的輔助方法。
方法 | 描述 |
---|---|
hexdump() | 以十六進(jìn)制的表示形式打印ByteBuf的內(nèi)容 |
equals(ByteBuf, ByteBuf) | 用來(lái)判斷兩個(gè)ByteBuf實(shí)例的相等性 |
?引用計(jì)數(shù)是一種通過(guò)在某個(gè)對(duì)象所持有的資源不再被其他對(duì)象引用時(shí)釋放該對(duì)象所持有的資源來(lái)優(yōu)化內(nèi)存使用和性能技術(shù)。
Netty為ByteBuf和ByteBufHolder引入了引用計(jì)數(shù)技術(shù),它們實(shí)現(xiàn)了ReferenceCounted接口。
試圖訪問(wèn)一個(gè)已經(jīng)被釋放的引用計(jì)數(shù)的對(duì)象,將會(huì)導(dǎo)致一個(gè)IllegalReferenceCountException
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69454.html
摘要:目前為止,我們已經(jīng)完成了一半的工作,剩下的就是在方法中啟動(dòng)服務(wù)器。第一個(gè)通常被稱為,負(fù)責(zé)接收已到達(dá)的。這兩個(gè)指針恰好標(biāo)記著數(shù)據(jù)的起始終止位置。 前言 本篇翻譯自netty官方Get Start教程,一方面能把好的文章分享給各位,另一方面能鞏固所學(xué)的知識(shí)。若有錯(cuò)誤和遺漏,歡迎各位指出。 https://netty.io/wiki/user-gu... 面臨的問(wèn)題 我們一般使用專用軟件或者...
時(shí)間:2018年04月11日星期三 說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):https://www.imooc.com 教學(xué)源碼:https://github.com/zccodere/s... 學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 什么是Netty 高性能、事件驅(qū)動(dòng)、異步非阻塞的IO Java開(kāi)源框架 基于NIO的客戶...
摘要:服務(wù)器構(gòu)成至少一個(gè)該組件實(shí)現(xiàn)了服務(wù)器對(duì)從客戶端接受的數(shù)據(jù)的處理,即它的業(yè)務(wù)邏輯引導(dǎo)配置服務(wù)器的啟動(dòng)代碼。至少,它會(huì)將服務(wù)器綁定到它要監(jiān)聽(tīng)連接請(qǐng)求的端口上。需要注意的是,由服務(wù)器發(fā)送的消息可能會(huì)被分塊接受。 Netty服務(wù)器構(gòu)成 至少一個(gè)ChannelHandler——該組件實(shí)現(xiàn)了服務(wù)器對(duì)從客戶端接受的數(shù)據(jù)的處理,即它的業(yè)務(wù)邏輯 引導(dǎo)——配置服務(wù)器的啟動(dòng)代碼。至少,它會(huì)將服務(wù)器綁定...
摘要:事件循環(huán)新連接接入連接上的數(shù)據(jù)讀取抽象連接抽象業(yè)務(wù)邏輯處理讀寫(xiě)數(shù)據(jù)期間的業(yè)務(wù)層動(dòng)態(tài)鏈處理多個(gè)組成,讓消息可以層層處理數(shù)據(jù)接收基本的數(shù)據(jù)處理基于公眾號(hào)貓說(shuō)學(xué)習(xí)交流群現(xiàn)架構(gòu)設(shè)計(jì)碼農(nóng)兼創(chuàng)業(yè)技術(shù)顧問(wèn),不羈平庸,熱愛(ài)開(kāi)源,雜談程序人生與不定期干貨。 本博客 貓叔的博客,轉(zhuǎn)載請(qǐng)申明出處閱讀本文約 4分鐘 適讀人群:同學(xué) Java IO,Socket非阻塞通信流程 這里我們使用一個(gè)內(nèi)嵌的永久循環(huán),...
摘要:轉(zhuǎn)發(fā)自 轉(zhuǎn)發(fā)自 http://netty.io/wiki/referenc... Since Netty version 4, the life cycle of certain objects are managed by their reference counts, so that Netty can return them (or their shared resources)...
閱讀 793·2021-11-11 16:54
閱讀 1528·2021-08-24 10:01
閱讀 1915·2019-08-30 15:54
閱讀 3300·2019-08-29 14:02
閱讀 3137·2019-08-28 18:22
閱讀 2249·2019-08-28 18:09
閱讀 3708·2019-08-26 10:26
閱讀 2673·2019-08-23 18:23