当前位置: 首页 > 后端技术 > Java

Netty系列:毫无疑问,netty中的ByteBuf比JAVA好用

时间:2023-04-02 00:58:49 Java

介绍Netty作为一个优秀的NIO框架,被广泛应用于各种服务器和框架中。同样是蔚来。netty所依赖的JDK在1.4版本已经提供了nio包。既然JDK已经有了nio包,为什么netty还要再写一个呢?不是因为JDK不好,而是netty的要求有点高。ByteBuf和ByteBuffer的可扩展性在说明netty中的ByteBuf有多么优秀之前,我们先来看看netty中的ByteBuf和jdk中的ByteBuffer的关系。其实没关系,只是名字有点相似罢了。jdk中的ByteBuffer,全称java.nio.ByteBuffer,属于JAVAnio包中的一个基础类。其定义如下:publicabstractclassByteBufferextendsBufferimplementsComparableandByteBufinnetty,全称io.netty.buffer,属于nettynio包中的一个基础类。它的定义如下:publicabstractclassByteBufimplementsReferenceCounted,Comparable两者的定义很相似,都是抽象类,都需要具体的类来实现。但是,当你尝试创建一个类来继承JDK的ByteBuffer时,你会发现无法继承。为什么一个名为abstract的类不能继承呢?仔细研究就会发现,在ByteBuffer中,定义了如下两个方法,并没有显式地标示其作用域访问:abstractbyte_get(inti);//包私有抽象void_put(inti,byteb);//package-private根据JDK的定义,没有显示标记作用域的方法,其访问默认为package。当这两个方法是抽象的时候,只有同一个包的类才能继承JDKByteBuffer。当然,JDK本身有五个ByteBuffer的实现,它们分别是DirectByteBuffer、DirectByteBufferR、HeapByteBuffer、HeapByteBufferR和MappedByteBuffer。但JDK将用户自定义类的扩展限制在ByteBuffer中。虽然这样可以保证ByteBuffer类在使用中的安全性,但是也呈现出用户需求的多样性。既然JDK的ByteBuffer不能扩容,那么netty中的ByteBuf自然就无计可施了。netty中的ByteBuff参考了JDK的ByteBuffer,做了很多有意义的改进,让ByteBuff更有用。与JDK的ByteBuffer相比,netty中的ByteBuf没有扩展限制,可以自由扩展修改。JDK中的ByteBuffer和netty中的ByteBuff的不同使用方式都提供了读写各类数据的功能。但是相对于netty中的ByteBuff,JDK中的ByteBuffer使用起来要复杂一些,因为它定义了4个值来描述ByteBuffer中的数据和用法。这四个值分别是:mark、position、limit和capacity。容量是它包含的元素的数量。容量永远不会是负数,也不会改变。limit是不应读取或写入的第一个元素的索引。limit永远不会是负数,也永远不会大于它的容量。position是下一个要读取或写入的元素的索引。position永远不会是负数,也永远不会大于它的限制。mark是调用reset方法时将重置其位置的索引。mark不一定有值,但是有值的时候永远不会是负数,永远不会大于position。以上4个值之间的关系是:0<=mark<=position<=limit<=capacity那么JDK也提供了3种方法来处理以上4个标记:clear:将limit设置为capacity,position设置为0,表示它可以被写。flip:将limit设置为当前位置,position设置为0,表示可以读取。rewind:limit不变,position设置为0,表示重新读取。是不是头大?太多的变量,太多的方法,虽然你现在可能还记得,但是过一段时间你就会忘记如何正确使用JDK的ByteBuffer。与JDK不同的是,netty中的ByteBuff只有两个索引,分别是readerIndex和writerIndex。除了索引,ByteBuff还提供了更丰富的读写API,方便我们使用。性能上的差异对于JDK的java.nio.ByteBuffer,当我们为它分配空间时,缓冲区会被0填充。虽然这些0可能马上被真正有意义的值代替。但不可否认的是,填充过程会消耗CPU和内存。另外,JDK的java.nio.ByteBuffer是依赖垃圾回收器进行回收的,不过我们之前说过,ByteBuffer有两种内部类型,一种是HeapBuffer,由JVM管理,使用垃圾回收器是没有问题的用于回收。但问题是还有另外一种ByteBuffer叫做DirectByteBuffer。这种Buffer直接分配在外存上,不受JVM管理。一般来说,DirectBuffer可能会存在很长时间。如果在短时间内分配了大量的短生命周期的对象,PeriodicDirectBuffer会导致这些Buffer来不及回收,从而导致OutOfMemoryError。另外,使用API??回收DirectBuffer的速度也没有那么快。相对来说netty中的ByteBuf使用的是一个自己管理的引用计数。当ByteBuf的引用计数归零时,底层内存空间将被释放或归还到内存池中。下面看看netty中直接ByteBuff的使用:ByteBufAllocatoralloc=PooledByteBufAllocator.DEFAULT;ByteBufbuf=alloc.directBuffer(1024);...buf.release();//回收directBuffer当然netty也是自己管理引用计数的一些缺点可能是pooledbuffer被垃圾回收后返回pool中的buffer,导致内存泄漏。好在netty提供了4种检测引用计数内存泄漏的方法,分别是:DISABLED---禁用泄漏检测SIMPLE--默认的检测方式,占buff的1%。高级-也检测到1%增益,但此选项将显示更多泄漏信息。偏执狂-检测所有增益。具体检测选项如下:java-Dio.netty.leakDetection.level=advanced...总结以上就是netty中优秀的ByteBuff与JDK的对比。不要急于使用它。本文已收录于http://www.flydean.com/45-netty-bytebuf-bytebuffer/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等着你等你发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!