热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

源码剖析_Netty专题源码剖析netty核心基础ByteBuf

本文由编程笔记#小编为大家整理,主要介绍了Netty专题源码剖析netty核心基础ByteBuf相关的知识,希望对你有一定的参考价值。在面
本文由编程笔记#小编为大家整理,主要介绍了Netty专题源码剖析netty核心基础ByteBuf相关的知识,希望对你有一定的参考价值。


在面试的时候,当面试问到netty的时候问到:你知道jdk nio中的ByteBuffernetty 中的ByteBuf有什么区别吗?来看看面试者的基础掌握的如何!你能准确回到出来个所以然吗?

说到jdk我先说说我身边使用jdk nio的情况;

我现在公司就有个游戏项目是jdk nio2一行一行实现的通讯架构,一直在线上运营,目前该架构单服承载最高的时候达到3000多人,没发现有什么性能瓶颈,当然人数可能还会继续增加,只要提高服务器配置,或者选择增加新的服务器去负载均衡;

我们都知道jdk nio臭名昭著的epoll bug,它会导致Selector空轮询,最终导致CPU 100%。官方声称在JDK1.6版本的update18修复了该问题;当然我没有遇到这个bug,希望后面也不要遇到(祈祷),而netty的设计就很自然的避免了这个问题;不用担心这个bug出现;

这篇文章就是由浅入深解读ByteBuf家族,从而彻底掌握ByteBuf各知识点。

 

一、先来比较下jdk nio中的ByteBuffernetty 中的ByteBuf

JDK NIO 劣势:

1、ByteBuffer给开发者的第一感觉就是他的API太少了,程序员的很多需求都不能满足,只能自己去实现或者做一下封装;

2、ByteBuffer 长度固定,不能动态收缩拓展,如果存很长的数据时候,就容易越界报错,例如:

  

3、ByteBuffer 读写操作的时候只有一个索引,操作起来flip(),rewind(),让人蛋疼,小白操作很容易混乱,这一点Mina IoBufferByteBuffer同病相怜;

 

相反netty 的ByteBuf解决上面的所有的痛点;丰富的API,支持动态收缩拓展,并且读写索引分开,不用操作字节的时候,那么蛋疼;

 

二、ByteBuf实现原理以及如何使用

Netty ByteBuf提供了2个指针变量分别用于顺序读取,和顺序写入,readerIndex是读索引,writerIndex是写索引,二者划分ByteBuf缓冲区关系:

 

【Netty专题】源码剖析netty核心基础ByteBuf


capacity:

 缓冲区的容量。

readerIndex:

【Netty专题】源码剖析netty核心基础ByteBuf

读取字节,改变readerIndex位置,或者下面的方法去初始化readerIndex


【Netty专题】源码剖析netty核心基础ByteBuf


  设置当前读的位置。可以使用readerIndex()和readerIndex(int)方法获取、设置readerIndex值。每次调用readXXX方法都会导致readerIndexwriterIndex移动,直到等于writerIndex为止。

writerIndex:

【Netty专题】源码剖析netty核心基础ByteBuf

  设置写的当前位置。可以使用writerIndex()和writerIndex(int)方法获取、设置writeIndex的值。每次调用writeXXX方法都会导致writeIndexcapacity移动,直到等于capacity为止。

discardable bytes:

【Netty专题】源码剖析netty核心基础ByteBuf

  表示读取之后丢弃,节约空间资源。0--readerIndex之间的数据长度是readerIndex - 0,调用discardReadBytes会丢弃这部分数据,把readerIndex--writerIndex之间的数据移动到ByteBuf的开始位置(0)


使用案例展示:

 

【Netty专题】源码剖析netty核心基础ByteBuf


三、ByteBuf缓冲分类

1、Heap buffer(堆缓冲区):

就是将数据存在JVM堆空间中,在没有被池化的情况可以快速分配和释放。

优点:由于数据是存储在JVM堆中,因此可以快速的创建与快速的释放,并且它提供了直接访问内部字节数组的方法。

缺点:每次读写数据时,都需要先将数据复制到直接缓冲区中再进行网路传输。

2、Direct buffer(直接缓冲区):

直接缓冲区,在堆外直接分配内存空间,直接缓冲区并不会占用堆的容量空间,因为它是由操作系统在本地内存进行的数据分配。

优点:在使用Socket进行数据传递时,性能非常好,因为数据直接位于操作系统的本地内存中,所以不需要从JVM将数据复制到直接缓冲区中 。

缺点:因为Direct Buffer是直接在操作系统内存中的,所以内存空间的分配与释放要比堆空间更加复杂,而且速度要慢一些。

注意:

如果你的数据包含在一个在堆上的分配的缓冲区中,那么事实上,在通过套接字发送他之前,jvm将会在内部把你的缓冲区复制到一个直接缓冲区中;这样分配释放就比较浪费资源;

建议:

直接缓冲区并不支持通过字节数组的方式来访问数据。对于后端业务的消息编解码来说,推荐使用HeapByteBuf;对于I/O通信线程在读写缓冲区时,推荐使用DirectByteBuf

3、Composite Buffer 复合缓冲区:

可以拥有以上两种的缓冲区,通过一种聚合视图来操作底层持有的多种类型Buffer。这种缓冲,jdk nio是没有这种特性的。

 

四、源码解读ByteBuf家族

 

【Netty专题】源码剖析netty核心基础ByteBuf


 

先看下ByteBuf的接口和他的三个不同方向的实现抽象类,下面还有具体实现类后面再具体列出来讲解,先介绍下这几个ByteBuf的顶级接口和抽象父类:

(Deprecated 的SwappedByteBuf官方已经不赞成去使用了,是不安全缓冲接口)

1、ReferenceCounted引用计数器接口。

  Netty 4开始,对象的生命周期由它们的引用计数(reference counts)管理,而不是由垃圾收集器(garbage collector)管理了。ByteBuf是最值得注意的,它使用了引用计数来改进分配内存和释放内存的性能。ByteBuf利用引用计数来改进分配和回收性能;

      只要引用计数大于 0,就能保证对象不会被释放。当活动引用的数量减少到时,该实例就会被释放;是由最后访问(引用计数)对象的那一方来负责将它释放。


【Netty专题】源码剖析netty核心基础ByteBuf

(1)、如果一个对象实现了ReferenceCounted接口,被初始化的时候,计数为1。

(2)、retain()方法能够增加计数,release() 方法能够减少计数,如果计数被减少到0则对象会被显示回收,再次访问被回收的这些对象将会抛出异常。

(3)、如果一个对象实现了ReferenceCounted,并且包含有其他对象也实现来ReferenceCounted,当这个对象计数为0被回收的时候,所包含的对象同样会通过release()释放掉。

 

2、Comparable:排序接口。

ByteBuf:定义了一下是否可读写的属性以及定义了一些读写操作的抽象接口,供子类继承实现。

 

【Netty专题】源码剖析netty核心基础ByteBuf


3、WrappedByteBuf:用于装饰ByteBuf对象,主要有AdvancedLeakAwareByteBufSimpleLeakAwareByteBufUnreleasableByteBuf三个子类。

(1)、WrappedByteBuf使用装饰者模式装饰ByteBuf对象

(2)、AdvancedLeakAwareByteBuf用于对所有操作记录堆栈信息,方便监控内存泄漏;

(3)、SimpleLeakAwareByteBuf只记录order(ByteOrder endianness)的堆栈信息;

(4)、UnreleasableByteBuf用于阻止修改对象引用计数器refCnt的值。

 

 

4、AbstractByteBuf: 抽象继承ByteBuf, ByteBuf缓冲的默认实现接口.

 

【Netty专题】源码剖析netty核心基础ByteBuf


 

子类很多,我们上面说的三种缓冲策略的类实现都是最终继承实现AbstracByteBuf,而AbstractByteBuf本身并没有具体去对不同ByteBuf缓冲区去做具体实现,而是由子类去实现,原因很简单父类不知道子类去实现堆内存还是直接内存,还是复合缓冲区;只是提供一个抽象接口而已;

再看看AbstractByteBuf源码中属性:

 

【Netty专题】源码剖析netty核心基础ByteBuf


 

定义了读,写索引和读写索引的标记,以及最大容量,leakDetectro:是监测内存是否泄漏,是static类型,说明是共享公共的对象;

 

AbstractByteBuf直接子类 AbstractDerivedByteBuf:提供派生ByteBuf的默认实现,主要有DuplicatedByteBufReadOnlyByteBufSlicedByteBuf

(1)、DuplicatedByteBuf:使用装饰者模式创建ByteBuf的复制对象,使得复制后的对象与原对象共享缓冲区的内容,但是独立维护自己的readerIndexwriterIndex

(2)、ReadOnlyByteBuf:使用装饰者模式创建ByteBuf的只读对象,该只读对象与原对象共享缓冲区的内容,但是独立维护自己的readerIndexwriterIndex,之后所有的写操作都被限制;

(3)、SlicedByteBuf:使用装饰者模式创建ByteBuf的一个子区域ByteBuf对象,返回的ByteBuf对象与当前ByteBuf对象共享缓冲区的内容,但是维护自己独立的readerIndexwriterIndex,允许写操作。

(4)、其实还可以按照另外一个维度去理解,一个是池化的ByteBuf一个是非池化的ByteBuf(用完就销毁);即PooledByteBuf_ 和UnpooledByteBuf_;

 

以上三种缓冲官方已经Deprecated不推介使用;

 

这也不推介使用那也不推介使用,那我们用哪些类去操作缓冲呢?

我们用AbstractByteBuf直接子类AbstractReferenceCountedByteBuf,该抽象类的子类实现的缓冲类;

 


 

上面我们看到很多实现类,而且没有一个被Deprecated的;这里只重点介绍几个常用的;

(1)、UnpooledDirectByteBuf

 在堆外进行内存分配的非内存池ByteBuf,内部持有ByteBuffer对象,相关操作委托给ByteBuffer实现。


(2)、UnpooledHeapByteBuf

  基于堆内存分配非内存池ByteBuf,即内部持有byte数组。


(3)、UnpooledUnsafeDirectByteBuf

  和另外一个类UnpooledDirectByteBuf差不多相同,区别在于UnpooledUnsafeDirectByteBuf内部使用基于PlatformDependent相关操作实现ByteBuf,依赖平台。


(4)、ReadOnlyByteBufferBuf

  只读ByteBuf,内部持有ByteBuffer对象,相关操作委托给ByteBuffer实现,该ByteBuf限内部使用;


(5)、FixedCompositeByteBuf

 用于将多个ByteBuf组合在一起,形成一个虚拟的只读ByteBuf对象,不允许写入和动态扩展。内部使用Object[]将多个ByteBuf组合在一起,一旦FixedCompositeByteBuf对象构建完成,则不会被更改。


(6)、CompositeByteBuf

 用于将多个ByteBuf组合在一起,形成一个虚拟的ByteBuf对象,支持读写和动态扩展。内部使用List组合多个ByteBuf一般使用使用ByteBufAllocatorcompositeBuffer()方法,Unpooled的工厂方法compositeBuffer()wrappedBuffer(ByteBuf... buffers)创建CompositeByteBuf对象。


(7)、PooledByteBuf

  基于内存池的ByteBuf,主要为了重用ByteBuf对象,提升内存的使用效率;适用于高负载,高并发的应用中。主要有PooledDirectByteBufPooledHeapByteBufPooledUnsafeDirectByteBuf三个子类,PooledDirectByteBuf是在堆外进行内存分配的内存池ByteBufPooledHeapByteBuf是基于堆内存分配内存池ByteBufPooledUnsafeDirectByteBuf也是在堆外进行内存分配的内存池ByteBuf,区别在于PooledUnsafeDirectByteBuf内部使用基于PlatformDependent相关操作实现ByteBuf,具有平台相关性。

 











  就到这里了,感谢读者认真读完;差不多就netty的ByteBuf家族有了初步的了解了,后面博客我会对三种缓冲(直接缓冲,复合缓冲,堆缓冲)进行具体源码剖析,和大家一起学习一起探讨;如有些的不对的地方,请积极指出,以便及时纠正。


















推荐阅读
  • CSS3选择器的使用方法详解,提高Web开发效率和精准度
    本文详细介绍了CSS3新增的选择器方法,包括属性选择器的使用。通过CSS3选择器,可以提高Web开发的效率和精准度,使得查找元素更加方便和快捷。同时,本文还对属性选择器的各种用法进行了详细解释,并给出了相应的代码示例。通过学习本文,读者可以更好地掌握CSS3选择器的使用方法,提升自己的Web开发能力。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 什么是网关服务器初学linux服务器开发时,我们的服务器是很简单的,只需要一个程序完成与客户端的连接,接收客户端数据,数据处理,向客户端发送数据。但是在处理量很大的情况下,一 ... [详细]
  • 朱晔的互联网架构实践心得S1E7:三十种架构设计模式(上)【下载本文PDF进行阅读】设计模式是前人通过大量的实践总结出来的一些经验总结和最佳实践。在经过多年的软件开发实践之后,回过头 ... [详细]
  • 基于PgpoolII的PostgreSQL集群安装与配置教程
    本文介绍了基于PgpoolII的PostgreSQL集群的安装与配置教程。Pgpool-II是一个位于PostgreSQL服务器和PostgreSQL数据库客户端之间的中间件,提供了连接池、复制、负载均衡、缓存、看门狗、限制链接等功能,可以用于搭建高可用的PostgreSQL集群。文章详细介绍了通过yum安装Pgpool-II的步骤,并提供了相关的官方参考地址。 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Tomcat/Jetty为何选择扩展线程池而不是使用JDK原生线程池?
    本文探讨了Tomcat和Jetty选择扩展线程池而不是使用JDK原生线程池的原因。通过比较IO密集型任务和CPU密集型任务的特点,解释了为何Tomcat和Jetty需要扩展线程池来提高并发度和任务处理速度。同时,介绍了JDK原生线程池的工作流程。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • 本文介绍了一个在线急等问题解决方法,即如何统计数据库中某个字段下的所有数据,并将结果显示在文本框里。作者提到了自己是一个菜鸟,希望能够得到帮助。作者使用的是ACCESS数据库,并且给出了一个例子,希望得到的结果是560。作者还提到自己已经尝试了使用"select sum(字段2) from 表名"的语句,得到的结果是650,但不知道如何得到560。希望能够得到解决方案。 ... [详细]
  • 本文详细介绍了如何使用MySQL来显示SQL语句的执行时间,并通过MySQL Query Profiler获取CPU和内存使用量以及系统锁和表锁的时间。同时介绍了效能分析的三种方法:瓶颈分析、工作负载分析和基于比率的分析。 ... [详细]
  • LVS-DR直接路由实现负载均衡示例
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • 域名解析系统DNS
    文章目录前言一、域名系统概述二、因特网的域名结构三、域名服务器1.根域名服务器2.顶级域名服务器(TLD,top-leveldomain)3.权威(Authoritative)域名 ... [详细]
  • 目录Atlas介绍Atlas部署Atlas基本管理Atlas结合MHA故障恢复读写分离建议Atlas介绍Atlas是由Qihoo360Web平台部基础架构团队开发维护的一个基于My ... [详细]
author-avatar
手机用户2502912633
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有