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