ByteBufHolder 接口
缓冲区除了实际的数据负载之外,还需要存储各种属性值,拿HTTP为例,除了表示为字节的内容,还包括状态码、cookie等。
ByteBufHolder提供的一些方法(不包括继承自引用计数的方法):
- content(),返回由这个ByteBufHolder持有的ByteBuf实例
- copy(),返回这个ByteBufHolder的一个深拷贝,包括一个其所包含的ByteBuf的非共享实例
- duplicate(),返回这个ByteBufHolder的一个浅拷贝,包括一个其所包含的ByteBuf共享实例
该接口主要用于自定义缓冲区类型的扩展字段,如上HTTP例子,状态码、cookie等数据的存储可以在继承DefaultByteBufHolder接口后做一些自定义的字段扩展。
ByteBuf分配
按需分配:ByteBufAlloctor接口
池化:为了降低分配和释放的内存锁开销,让ByteBuf先放到缓冲区池中,不立即销毁,用的时候直接取池里面的ByteBuf实例,Netty通过ByteBufAlloctor接口实现池化。
ByteBufAlloctor的实现:
- PooledByteBufAllocator,池化了ByteBuf实例以提高性能并最大限度减少内存,Netty默认使用这个,可以很容易的通过ChannelConfig接口或者在引导应用程序时指定一个不同的分配器。
- UnPooledByteBufAllocator,不池化ByteBuf实例,每次调用它都会返回一个新的实例
ByteBufAlloctor的方法:
- buffer(),返回一个基于堆或者直接内存存储的ByteBuf
- heapBuffer(),返回一个基于堆内存存储的ByteBuf
- directBuffer(),返回一个基于直接内存存储的ByteBuf
- compositeBuffer()、compositeDirectBuffer()、compositeHeapBuffer(),返回一个可以通过添加最大到指定数据的基于堆或者直接内存存储的缓冲区来扩展CompositeByteBuf
- ioBuffer(),返回一个用于套接字的IO操作的ByteBuf
获取一个到ByteBufAllocator的引用:
可以通过Channel(每个通道都可以有不同的ByteBufAllocator实例)或者绑定到ChannelHandler的ChannelHandlerContext获取,调用alloc()方法。
Unpooled缓冲区
如果某些下你未能获取到一个ByteBufAllocator的引用,可以通过Unpooled工具类获取一个未池化的实例,提供了静态的辅助方法:
- buffer(),返回一个未池化的基于堆内存存储的ByteBuf
- directBuffer(),返回一个未池化的基于直接内存存储的ByteBuf
- wrappedBuffer(),返回一个包装了给定数据的ByteBuf
- copiedBuffer(),返回一个复制了给定数据的ByteBuf,这个案例用的挺多的
Unpooled可用于并需要Netty的其他组件的非网络项目,使其能获取到高性能的可扩展的缓冲区接口。
ByteBufUtil
提供了用于操作ByteBuf的静态辅助方法,和池化无关,常用的方法:
- hexdump(),以十六进制的标识形式打印ByteBuf内容
- equals(),用来判断两个ByteBuf实例的相等
引用计数
引用计数通过在某个对象所持有的资源不在被其他对象引用时释放该对象所持有的资源来优化使用和性能的技术。
ByteBuf和ByteBufHolder都实现了引用计数接口ReferenceCounted,主要的原理:
跟踪某个特定对象的活动引用的数量,一个ReferenceCounted实现的实例通常以活动的引用计数为1作为开始,只要引用计数大于0,就能保证对象不会被释放,当活动引用的数量减少到0时便自动释放该对象。
ReferenceCounted方法:
- refCnt(),获取活动引用的数量
- release(),减少该对象的活动引用,为0时自动释放并返回true
一般由最后访问该实例的那一方来负责将它释放。
