网络数据的基本单位是字节,那么在JavaNIO和netty分别用什么作为字节容易呢?
在JavaNIO中使用ByteBuffer作为字节容器,Netty使用ByteBuf
Netty的数据处理API通过两个组件暴露出来,一个是ByteBuf,一个是ByteBufHolder
-------
跟ByteBuffer相比,ByteBuf有以下几个优点(个人觉得比较重要的几个点):
1.通过内置的复合缓冲区类型实现了透明的零拷贝
2.容量可以按需增长(类似于JDK的StringBuilder)
3.在读和写之间的切换无需像ByteBuffer一样使用flip()进行切换,而是通过维护读写索引
---------
ByteBuf是如何工作的?
从最基本的读写操作开始,ByteBuf主要维护了两个不同的索引,一个用于读取,一个用于写入
readIndex和writeIndex的起始值都为0,随着以read和write开头的方法操作后,索引随之增加,当然ByteBuf也提供了get和set的操作api,但是他们不移动索引,他们只是移动了一个相对索引。
---------
ByteBuf有多少种工作模式?
1.堆缓冲区
这是ByteBuf最常用的模式,直接将数据存储在JVM的堆空间中,这种模式被称为支撑数组,它能在没有池化的情况下提供快速的分配和释放
2.直接缓冲区
NIO在JDK1.4中引入了ByteBuffer类允许JVM实现通过本地调用来分配内存。这主要是为了避免在每次调用本地IO操作之前将缓冲区的内容复制到一个中间缓冲区。直接缓冲区是网络数据传输最佳的选择,因为从根本上看,堆缓冲区最后也会被JVM复制到直接缓冲区后,才通过套接字发送它们
3.复合缓冲区
复合缓冲区为多个缓冲区提供了一个聚合视图,通过一个子类CompositeByteBuf提供一个将多个缓冲区表示为单个合并缓冲区的虚拟表现
(这个复合缓冲区我不是很懂,后面我再来补,溜了。。。)
---------
字节级操作
1.ByteBuf维护了2个索引,一个readIndex一个writeIndex
2.随着读操作的进行,readIndex会随之增大,Netty提供了API可以删除掉前面已经被读取的字节,通过调用discardReadBytes()可以丢弃他们并且回收空间
3.关于discardReadBytes()有利也有弊,频繁调用discardReadBytes可以确保可写分段的最大化,但是这极有可能导致内存复制,因为可读字节必须被移动到缓冲区的开始位置。
4.同样调用clear()也可以将readIndex和writeIndex设置为0,但是它不会丢弃前面的内容。调用clear比discardReadBytes轻量得多,因为它将只是重置索引而不会复制任何的内存
---------
派生缓冲区
ByteBuf提供一些方法api来生成一个新的实例
duplicate()
slice()
slice(int,int)
Unpooled.unmodifiableBuffer()
order(ByteOrder)
readSlice(int)
这些方法都会返回一个实例,不过内容也是共享的,修改了其中的内容,源头也会被随之修改,在我看来,这和Java的浅复制概念差不多,但是如果真的需要一个现有的缓冲区的真实副本,可以使用copy()或者copy(int,int)方法,调用返回的是一个拥有独立副本数据的数据副本
---------
ByteBufHolder
Netty提供了ByteBufHolder。ByteBufHolder为Netty的高级特性提供了支持,如缓冲区池化
---------
ByteBuf的分配
为了降低分配和释放内存的开销,Netty通过ByteBufAllocator实现了池化,它可以用来分配我们所描述过的任意类型的ByteBuf的实例。它有很多API方法可以返回ByteBuf的,这里就不列出了,主要返回基于上面提到的几种类型的缓冲区的ByteBuf。还可以返回一个用于套接字的IO操作的ByteBuf
Netty提供了两种ByteBufAllocator的实现:PooledByteBufAllocator和UnpooledByteBufAllocator。前者池化了ByteBuf的实例以提高性能并能最大限度地减少内存碎片。后者实现不池化ByteBuf实例,每次调用都是返回一个新的实例。Netty默认使用了前者,当然这是可以配置的。
Netty提供了一个工具类Unpooled,它可以获取一些未被池化的基于缓冲区的ByteBuf
同样Netty也提供了一些工具类,例如ByteBufUtil,其中有一个很有用的API可以比较两个ByteBuf
Netty还引入了引用计数的概念,它可以方便我们自己手动管理内存
ByteBuf和ByteBufHolder都实现了ReferenceCounted的接口
今天就分享到这里,这些都是从《Netty实战》中提取的一些笔记,如有侵权,请联系我删除