readSlice、readRetainedSlice
返回部分空间,彼此共享底层缓冲区,会增加原缓冲区的readerIndex。
如果需要一个现有缓冲区的真实副本,请使用 copy()或者 copy(int, int),因为这个调用所返回的 ByteBuf 拥有独立的数据副本。
引用与释放
ByteBuf 在使用完毕后一定要记得释放,否则会造成内存泄露。
引用计数
通过在某个对象所持有的资源不再被其他对象引用时释放该对象所持有的资源来优化内存使用和性能的技术。
Netty 在4.x为 ByteBuf 和 ByteBufHolder 带来了引用计数技术,都实现了:
ReferenceCounted接口
需要显式释放的引用计数对象。
当一个新的ReferenceCounted被实例化时,以1 作为初始值。
retain()
增加引用计数,将引用计数加1。只要引用计数>0,就能保证对象不会被释放。
release()
减少引用计数,将引用计数减1。若引用计数减少到0 ,对象将被显式释放,并且访问释放的对象通常会导致访问冲突。
若实现ReferenceCounted的对象是其他实现ReferenceCounted的对象的容器,则当容器的引用计数变为 0 时,所包含的对象也将通过release()被释放。
引用计数对于池化实现(如 PooledByteBufAllocator)很重要,它降低了内存分配的开销。
Channel channel = ...; // 从 Channel 获取 ByteBufAllocator ByteBufAllocator allocator = channel.alloc(); ... // 从 ByteBufAllocator 分配一个 ByteBuf ByteBuf buffer = allocator.directBuffer(); // 检查引用计数是否为预期的 1 assert buffer.refCnt() == 1; ByteBuf buffer = ...; // 减少该对象的活动引用。当减少到 0 时,该对象被释放,该方法返回 true boolean released = buffer.release();
试图访问一个已经被释放的引用计数的对象,将会抛IllegalReferenceCountException
一个特定的(ReferenceCounted 的实现)类,可以用它自己的独特方式来定义它的引用计数规则。例如可以设想一个类,其 release()方法的实现总是将引用计数设为
零,而不用关心它的当前值,从而一次性使所有的活动引用都失效。
谁负责释放
一般由最后访问(引用计数)对象的那一方来负责将它释放。