ByteBuf是Java NIO ByteBuffer的替代品,是网络数据基本单位字节的容器。数组
Netty的数据处理API经过两个组件暴漏:抽象类ByteBuf和接口ByteBufHolder网络
ByteBuf优势:app
ByteBuf维护两个索引:一个用于读取,一个用于写入。当你从ByteBuf读取时,readIndex会被递增已经被读取的字节数,一样的,当向ByteBuf中写入数据时,writeIndex也会被递增。
若是readIndex和writeIndex处于一样的位置,再次尝试读取数据将会触发IndexOutOfBoundsException工具
名称以read或者write开头的ByteBuf方法,将会推动其对应的索引,而名称以set或者get开头的操做则不会。性能
名称以set或者get开头的方法会有一个索引位置参数,将会在该索引位置上进行set或get操做优化
ByteBuf能够指定最大容量。若是写索引超过这个值会触发异常IllegalArgumentException。默认的最大值是Integer.MAX_VALUEspa
将数据存储在JVM的对空间中,这种模式又被成为支撑数组。它能在没有使用池化的状况下提供快速的分配和释放。对象
当hasArray方法返回false时,尝试访问支撑数组将触发UnsupportedOperationException异常。索引
NIO引入的ByteBuffer类容许JVM实现经过本地调用来分配内存,这样能够避免在每次调用本地I/O操做以前(或者以后)将缓冲区的内容复制到一个中间缓冲区(或者从中间缓冲区把内容复制到缓冲区)。接口
直接缓冲区的主要特色是,分配和释放都比较昂贵。
它为多个ByteBuf提供了一个聚合视图。能够根据须要添加或者删除ByteBuf实例。Netty经过CompositeByteBuf(ByteBuf的子类)实现这个模式,它提供了一个将多个缓冲区表示为单个合并缓冲区的虚拟表示。
CompositeByteBuf中的ByteBuf实例可能同时包含直接内存分配和非直接内存分配。若是只有一个ByteBuf实例,那么CompositeByteBuf上的hasArray方法将返回该ByteBuf上的hasArray方法的值,不然将返回false。
CompositeByteBuf不支持访问支撑数组,所以访问CompositeByteBuf中的数据相似于访问直接缓冲区的模式。
Netty使用CompositeByteBuf来优化套接字I/O操做,尽量消除由JDK的缓冲区实现所致使的性能以及内存使用率的惩罚,这种优化发生在Netty的核心代码中,不会被暴露出来。
ByteBuf的索引是从0开始:第一个字节的索引就是0,最后一个字节的索引是capacity() - 1。
若是方法中有一个索引值参数,经过该方法访问数据既不会改变readIndex也不会改变writeIndex。
若是有须要,能够经过调用readIndex(index)或者writeIndex(index)手动移动二者。
ByteBuf内部分段示意图以下:
在上图中可丢弃字节指的就是已被读取过的字节,经过调用discardReadBytes()方法,能够丢弃它们并回收空间。可丢弃字节分段的初始大小为0,即readIndex,该值会随着read操做的执行而增长(get*操做不会移动readIndex)。
discardReadBytes()方法只是移动了能够读取的字节以及writeIndex,而没有对全部可写入的字节进行擦除写。
discardReadBytes()会致使内存复制,由于可读字节必需要移动到缓冲区开始的位置。
可读字节分段存储了实际数据。新分配的、包装的或者复制的缓冲区的默认readINdex值为0。任何名称以read或者skip开头的操做都将检索或者跳过位于当前readIndex的数据,并将它增长已读字节数。
若是被调用的方法须要一个ByteBuf参数做为写入的目标,而且没有指定目标索引参数,那么该写入的目标的writeIndex也将被增长。
能够字节分段是指一个拥有未定义内容的、写入就绪的内存区域。新分配的缓冲区的writeIndex的默认值为0。任何以write开头的方法都将从当前的writeIndex开始写数据,并将它增长已经写入的字节数。若是写操做的目标也是ByteBuf,而且没有指定源索引的值,则源缓冲区的readerIndex也会被增长相同的大小。
JDK的InputStream定义了mark(int readLimit)和reset()方法,这些方法分别被用来将流中的当前位置标记为指定的值,以及将流重置到该位置。
在ByteBuf中,能够调用markReadIndex()、markWriteIndex()、resetReaderIndex()、resetWriterIndex()来标记和重置ByteBuf的readIndex和writeIndex,不过在ByteBuf中没有readLimit参数指定标记啥时候失效。
在ByteBuf中,也能够经过调用readerIndex(int)或者writeIndex(int)来将索引移动到指定位置。
在ByteBuf中,能够经过clear()方法将readerIndex和writeIndex都设置为0,可是不会清楚内存中的内容。调用clear()方法比调用discardReadBytes()更加轻量,由于clear只是重置索引,不会复制任何的内存。
最简单的肯定值的索引的方法是indexOf()。较复杂的查找能够经过一个ByteProcessor(Netty4.1版本以上,旧的版本采用ByteBufProcessor)参数达成。
派生缓冲区为ByteBuf提供了以专门的方式来呈现其内容的视图,这类视图的建立方式主要有如下几种:
以上方法都会返回一个新的ByteBuf实例,它具备本身的读索引、写索引和标记索引。它会和源实例共享内存,所以建立成本低廉,可是若是修改它的内容,也就意味着修改了对应的源实例。
若是须要一个现有缓冲区的真实副本,须要使用copy()或者copy(int,int)方法
读写操做主要分为两类:
方法名称 | 描述 |
---|---|
getBoolean(int) | 返回给定索引处的Boolean值 |
getByte(int) | 返回给定索引处的字节 |
getUnsignedByte(int) | 将给定索引处的无符号字节值做为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, ...) | 将该缓冲区中从给定索引开始的数据传送到指定的目的地 |
方法名称 | 描述 |
---|---|
setBoolean(int, boolean) | 设定给定索引处的Boolean值 |
setByte(int index, int value) | 设定给定索引处的字节值 |
setMedium(int index, int value) | 设定给定索引处的24位的中等int值 |
setInt(int index, int value) | 设定给定索引处的int值 |
setLong(int index, long value) | 设定给定索引处的long值 |
setShort(int index, int value) | 设定给定索引处的short值 |
方法名称 | 描述 |
---|---|
readBoolean() | 返回当前readIndex处的Boolean值,并将readIndex增长1 |
readByte() | 返回当前readIndex处的字节,并将readIndex增长1 |
readUnsignedByte() | 将当前readIndex处的无符号字节值做为short返回,并将readIndex增长1 |
readMedium() | 返回当前readIndex处的24位的中等int值,并将readIndex增长3 |
readUnsignedMedium() | 返回当前readIndex处的24位的无符号的中等int值,并将readIndex增长3 |
readInt() | 返回当前readIndex处的int值,并将readIndex增长4 |
readUnsignedMedium() | 返回当前readIndex处的24位的无符号的中等int值,并将readerIndex增长3 |
readInt() | 返回当前readIndex处的int值,并将readerIndex增长4 |
readUnsignedInt() | 将当前readerIndex处的无符号的int值做为long值返回,并将readIndex增长4 |
readLong() | 返回当前readIndex处的long值,并将readIndex增长8 |
readShort() | 返回当前readIndex处的short值,并将readIndex增长2 |
readUnsignedShort() | 将当前readIndex处的无符号short值做为int值返回,并将readIndex增长2 |
readBytes(ByteBuf byte[] destination, int dstIndex, [, int length]) | 将当前ByteBuf中从当前readIndex处开始的(若是设置了,length长度的字节)数据传送到一个目标ByteBuf或者byte[],从目标的dstIndex开始的位置。本地的readIndex将被增长已经传输的字节数。 |
方法 | 描述 |
---|---|
writeBoolean(boolean) | 在当前writeIndex处写入一个boolean值,并将writeIndex增长1 |
writByte(byte) | 在当前writeIndex处写入一个字节值,并将writeIndex增长1 |
writeMedium(int) | 在当前writeIndex处写入一个中等的int值,并将writeIndex增长3 |
writeInt(int) | 在当前writeIndex处写入一个int值,并将writeIndex增长4 |
writeLong(long) | 在当前writeIndex处写入一个long值,并将writeIndex增长8 |
writeShort(int) | 在当前writeIndex处写入一个short值,并将writeIndex增长2 |
writeBytes(source ByteBuf byte[] [,int srcIndex,int length]) | 从当前writeIndex开始,传输来自于指定源(ByteBuf或者byte[])的数据。若是提供了srcIndex和length,则从srcIndex开始读取,而且处理长度为length的字节。当前writeIndex将会被增长所写入的字节数。 |
方法 | 描述 |
---|---|
isReadable() | 若是至少有一个字节可供读取,则返回true |
isWritable() | 若是至少有一个字节可被写入,则返回true |
readableBytes() | 返回可被读取的字节数 |
writableBytes() | 返回可被写入的字节数 |
capacity() | 返回ByteBuf可容纳的字节数。在此以后,它会尝试再次扩展直到达到maxCapacity() |
maxCapacity() | 返回ByteBuf能够容纳的最大字节数 |
hasArray() | 若是ByteBuf由一个字节数组支撑,则返回true |
array() | 若是ByteBuf由一个字节数组支撑则返回该数组;不然,它将抛出一个UnsupportedOperationException异常 |
ByteBufHolder为Netty的高级特性提供了支持,如缓冲区池化,其中能够从池中借用ByteBuf,而且在须要时自动释放。
名称 | 描述 |
---|---|
content() | 返回由这个ByteBufHolder所持有的ByteBuf |
copy() | 返回这个ByteBufHolder的一个深拷贝,包括一个其所包含的ByteBuf的非共享拷贝 |
duplicate() | 返回这个ByteBufHolder的一个浅拷贝,包括一个其所包含的ByteBuf的共享拷贝 |
为了下降分配和释放内存的开销,Netty经过ByteBufAllactor接口实现了(ByteBuf的)池化,它能够用来分配咱们所描述过的任意类型的ByteBuf实例。
名称 | 描述 |
---|---|
buffer() buffer(int initialCapacity) buffer(int initialCapacity, int maxCapacity) |
返回一个基于堆或者直接内存存储的ByteBuf |
heapBuffer() heapBuffer(int initialCapacity) heapBuffer(int initialCapacity, int maxCapacity) |
返回一个基于堆内存存储的ByteBuf |
directBuffer() directBuffer(int initialCapacity) directBuffer(int initialCapacity, int maxCapacity) |
返回一个基于直接内存存储的ByteBuf |
compositeBuffer() compositeBuffer(int maxNumComponents) compositeDirectBuffer() compositeDirectBuffer(int maxNumComponents) compositeHeapBuffer() compositeHeapBuffer(int maxNumComponents) |
返回一个能够经过添加最大到指定数目的基于堆的或者直接内存存储的缓冲区来扩展的CompositeByteBuf |
ioBuffer() | 返回一个用于套接字的I/O操做的ByteBuf |
Netty提供了两种ByteBufAllocator的实现:PooledByteBufAllocator和ByteBufAllocator。前者池化了ByteBuf的实例以提升性能并最大限度的减小内存碎片,后者的实现不池化ByteBuf实例,而且每次被调用时都会返回一个新的实例。
Netty4.1之后默认使用PooledByteBufAllocator
Netty提供了一个简单的成为Unpooled的工具类,它提供了静态的辅助方法来建立未池化的ByteBuf实例。
方法 | 描述 |
---|---|
buffer() buffer(int initialCapacity) buffer(int initialCapacity, int maxCapacity) |
返回一个未池化的基于堆内存存储的ByteBuf |
directBuffer() directBuffer(int initialCapacity) directBuffer(int initialCapacity, int maxCapacity) |
返回一个未池化的基于直接内存存储的ByteBUf |
wrappedBuffer() | 返回了一个包装了给定数据的ByteBuf |
copiedBuffer() | 返回了一个复制了给定数据的ByteBuf |
ByteBufUtil提供了用于操做ByteBuf的静态的辅助方法。
方法 | 描述 |
---|---|
hexdump() | 以十六进制的表示形式打印ByteBuf的内容 |
equals(ByteBuf, ByteBuf) | 用来判断两个ByteBuf实例的相等性 |
引用计数是一种经过在某个对象所持有的资源再也不被其余对象引用时释放该对象所持有的资源来优化内存使用和性能技术。
Netty为ByteBuf和ByteBufHolder引入了引用计数技术,它们实现了ReferenceCounted接口。
试图访问一个已经被释放的引用计数的对象,将会致使一个IllegalReferenceCountException