Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

ByteBuf是Netty中主要的数据容器与操作工具,也是Netty内存管理优化的具体实现,本章我们先从整体上对ByteBuf进行一个概述;

AbstractByteBuf是整个ByteBuf的框架类,定义了各种重要的标志位与API供具体的实现类使用与实现;下面我们就从AbstractByteBuf类入手对ByteBuf的读写机制与API进行一个简单的介绍

private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractByteBuf.class);
    private static final String LEGACY_PROP_CHECK_ACCESSIBLE = "io.netty.buffer.bytebuf.checkAccessible";
    private static final String PROP_CHECK_ACCESSIBLE = "io.netty.buffer.checkAccessible";
    static final boolean checkAccessible; // accessed from CompositeByteBuf
    private static final String PROP_CHECK_BOUNDS = "io.netty.buffer.checkBounds";
    private static final boolean checkBounds;

    static {
        if (SystemPropertyUtil.contains(PROP_CHECK_ACCESSIBLE)) {
            checkAccessible = SystemPropertyUtil.getBoolean(PROP_CHECK_ACCESSIBLE, true);
        } else {
            checkAccessible = SystemPropertyUtil.getBoolean(LEGACY_PROP_CHECK_ACCESSIBLE, true);
        }
        checkBounds = SystemPropertyUtil.getBoolean(PROP_CHECK_BOUNDS, true);
        if (logger.isDebugEnabled()) {
            logger.debug("-D{}: {}", PROP_CHECK_ACCESSIBLE, checkAccessible);
            logger.debug("-D{}: {}", PROP_CHECK_BOUNDS, checkBounds);
        }
    }

    static final ResourceLeakDetector leakDetector =
            ResourceLeakDetectorFactory.instance().newResourceLeakDetector(ByteBuf.class);

    int readerIndex;
    int writerIndex;
    private int markedReaderIndex;
    private int markedWriterIndex;
    private int maxCapacity;

在上面的代码中,我们需要知道ByteBu维护了两个不同的索引readerIndex与writerIndex,这两个索引默认都是从0开始,一个用于读取,一个用于写入。

Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

当你从ByteBuf读取数据时,readerIndex会递增已经读取的字节数,同理当你写入数据时,writerIndex也会随之递增。可以说ByteBuf中各种读写API都是基于readerIndex与writerIndex来控制的。从索引操作上,ByteBuf中API基本分为两大部分,会引发索引值递增的read(读)和write(写操作),反之不会引发索引值递增的get或set操作。下面我们看下ByteBu中常用API的参考说明

ByteBuf API

read操作

readBoolean() 返回当前readIndex的Boolean值,readIndex增加1 readByte(int) 返回当前readIndex处的字节值,readIndex增加1 readUnsignedByte() 返回当前readIndex处的无符号字节值,readIndex增加1 readInt() 返回当前readIndex处的int值,readIndex增加4 readUnsignedInt() 返回当前readIndex处的无符号int值,返回类型为long,readIndex增加4 readLong() 返回当前readIndex处的long值,readIndex增加8 readShort()

返回当前readIndex处的short值,readIndex增加2

readUnsignedShort() 返回当前readIndex处的short值,readIndex增加2

wirte操作

writeBoolean() 在当前writerIndex处写入一个Boolean值(1或0),writerIndex增加1 writeByte(int) 在当前writerIndex处写入一个byte值,writerIndex增加1 writeShort(int) 在当前writerIndex处写入一个short值,writerIndex增加2 writeInt(int) 在当前writerIndex处写入一个int值,writerIndex增加4 writeLong(int) 在当前writerIndex处写入一个long值,writerIndex增加4

get操作

getBoolean(int) 返回给的索引处的Boolean值,readIndex值不变 getByte(int) 返回给的索引处的Byte值,readIndex值不变 getShort(int) 返回给的索引处的short值,readIndex值不变 getInt(int) 返回给的索引处的int值,readIndex值不变 getLong(int) 返回给的索引处的long值,readIndex值不变

set操作

setBoolean(int,boolean) 在指定索引处设置一个Boolean值(1或0),writerIndex值不变 setByte(int,int) 在指定索引处设置一个byte值,writerIndex值不变 setShort(int,int) 在指定索引处设置一个short值,writerIndex值不变 setInt(int,int) 在指定索引处设置一个int值,writerIndex值不变 setLong(int,int) 在指定索引处设置一个long值,writerIndex值不变

ByteBuf类型

Netty中ByteBuf相关实现类的UML图

Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

Netty在构建ByteBuf时,有以下多种分类:

1、从内存类型上,分为堆内存与直接内存,HeapByteBuf与DirectByteBuf

我们知道Java中大部分对象都是在堆内存中存储,由jvm统一管理,但NIO中 的 ByteBuffer 类允许 JVM 实现通过本地调用来分配内存,Netty中对基于直接内存的ByteBuffer也进行了封装,这主要是为了避免在每次调用本地 I/O 操作之前(或者之后)将缓冲区的内容复 制到一个中间缓冲区(或者从中间缓冲区把内容复制到缓冲区),直接缓冲区不会占用堆的容量。事实上,在通过套接字发送它之前,JVM将会在内部把你的缓冲 区复制到一个直接缓冲区中。所以如果使用直接缓冲区可以节约一次拷贝,提高IO操作性能。使用直接内存的优缺点如下:

(1)优点:由于数据直接在内存中,不存在从JVM拷贝数据到直接缓冲区的过程,提高IO操作性能。

(2)缺点:相对于基于堆的缓冲区,它们的分配和释放都较为昂贵,同时由于直接内存不受JVM垃圾回收统一管理,需要自己手动回收,需要特别注意内存泄露的问题。

2、从分配模式上,分为池化与非池化;PooledByteBuf与UnpooledByteBuf

对于频繁的申请与释放内存带来的性能损耗与碎片化问题,Netty基于池化思想通过预先申请一块专用内存地址作为内存池进行管理,从而不需要每次都进行分配和释放。

从上面的UML图中可以看到,基于AbstractByteBuf父类针对直接内存与堆内存,也都有其对应的池化与非池化实现类;

PooledByteBuf 下有 PooledUnsafeDirectByteBuf、PooledHeapByteBuf、PooledDirectByteBuf三个子类实现

UnpooledByteBuf 下则是 UnpooledDirectByteBuf及其子类UnpooledUnsafeDirectByteBuf 与 UnpooledHeapByteBuf及其子类UnpooledUnsafeHeapByteBuf

3、从具体的操作类上,分为Unsafe与非Unsafe

从上面的子类实现中,我们发现每种分类中又包含Usafe与非Unsafe的区别,我们知道java可以通过Unsafe类直接操作内存区域,所以这些类的区别就是在于是调用jdk的Unsafe直接去操作对象的内存地址还是通过jdk封装的安全方式操作内存。

我们通过PooledByteBuf下Unsafe与非Unsafe实现类的getByte方法,看下具体的区别

PooledUnsafeHeapByteBuf

@Override
    protected byte _getByte(int index) {
        return UnsafeByteBufUtil.getByte(addr(index));
    }

Netty中封装了一个UnsafeByteBufUtil类,进入内部实现看到调用的是Unsafe对象进行具体操作

static byte getByte(long address) {
        return UNSAFE.getByte(address);
    }

PooledHeapByteBuf

跟踪其内部代码则可以看到字节是基于数组操作的

@Override
    protected byte _getByte(int index) {
        return HeapByteBufUtil.getByte(memory, idx(index));
    }

    static byte getByte(byte[] memory, int index) {
        return memory[index];
    }

PooledDirectByteBuf

针对DirectByteBuf大家需要灵活理解,PooledUnsafeDirectByteBuf 与PooledUnsafeDirectByteBuf的区别一个是UnsafeByteBufUtil类直接操作,一个是使用java NIO中的DirectByteBuf类进行操作,但因为要操作直接内存,最后还都是要基于jdk的unsafe类实现;

对比他们两种实现,可以看出Unsafe与非Unsafe的区别,前者是通过jdk的Unsafe类去操作数据,后者直接通过数组或者jdk底层的DirectByteBuf去操作数据。

ByteBuf作为Netty中数据操作与内存分配的具体实现,是Netty中最为底层的也是最精细的一部分,本文只是对ByteBuf的一个简单概述,后续我们会进一步对其进行探索与剖析,更好的展示Netty内部具体实现,希望对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。

关注微信公众号,查看更多技术文章。

Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

转载说明:未经授权不得转载,授权后务必注明来源(注明:来源于公众号:架构空间, 作者:大凡)

Original: https://www.cnblogs.com/dafanjoy/p/13530708.html
Author: DaFanJoy
Title: Netty源码分析之ByteBuf(一)—ByteBuf中API及类型概述

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/593439/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • spring boot(书籍摘录和部分纯洁的微笑博客)

    Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度…

    Java 2023年6月7日
    045
  • Mybatis 请求参数Integer类型值为0源码处理

    mybatis在做条件查询时,如果传⼊参数为Integer类型且值为0时,如下代码,status!=”的值为false为什么?mybatis把0转成空串了?看到⽹上的答…

    Java 2023年5月30日
    092
  • Java中简单易懂的HashMap面试题(面试必备)

    这篇文章仅限小编个人的理解,小编不是Java方向的,只是对Java有很高的学习兴趣如果有什么不对的地方还望大佬指点 HashMap的底层是数组+链表,(很多人应该都知道了)JDK1…

    Java 2023年5月29日
    073
  • 简单易懂讲注解

    注解是什么 简单的说,注解就是一种将元数据信息从 xml 剥离开来,然后保存在 java 源代码中,这将使得代码更加清晰易懂,无需维护两个地方: java 源代码以及 xml 配置…

    Java 2023年6月8日
    077
  • 【Java面试手册-算法篇】给定一个整型数组,请判断是否为回文数组?

    对于一个给定的由正整数组成的数组 A[] ,如果将 A 倒序后数字的排列与 A 完全相同,则成数组A为回文数组。比如 [1, 2, 3, 2, 1] 是回文数组,而 [1, 2, …

    Java 2023年6月8日
    0105
  • 力扣刷题之路—–数组的遍历

    参考刷题顺序:力扣刷题顺序 本文章做自我总结,总结做题时自己的想法以及官方解题思路。 涉及题目 485 最大连续 1 的个数 495 提莫攻击 414 第三大的数 628 三个数的…

    Java 2023年6月5日
    0101
  • 教学日志:javaSE-面向对象2

    一、局部变量和成员变量 package class4.oop1; /** * @Auther: Yu Panpan * @Date: 2021/12/10 – 12 – 10 – …

    Java 2023年6月5日
    091
  • java 程序运行的基础知识【Java bytecode】

    每一个JVM线程来说启动的时候都会创建一个私有的线程栈。一个jvm线程栈用来存储栈帧,jvm线程栈和C语言中的栈很类似,它负责管理局部变量、部分运算结果,同时也参与到函数调用和函数…

    Java 2023年6月15日
    059
  • selenium 常见面试题以及答案(Java版)

    1.怎么 判断元素是否存在? 判断元素是否存在和是否出现不同, 判断是否存在意味着如果这个元素压根就不存在, 就会抛出 NoSuchElementException 这样就可以使用…

    Java 2023年5月29日
    0126
  • synchronized 是可重入锁吗?为什么?

    什么是可重入锁? 若一个程序或子程序可以”在任意时刻被中断然后操作系统调度执行另外一段代码,这段代码又调用了该子程序不会出错”,则称其为可重入(reentr…

    Java 2023年6月14日
    072
  • java_day04

    :: :: :: :: ::java_day04 Java基础 包机制 包实质上就是文件夹 *一般利用公司域名倒置作为包名 JavaDoc javadoc命令是用来生成自己的API…

    Java 2023年6月5日
    069
  • 兹瓷查rank和kth的STL平衡树

    兹瓷查rank和kth的STL平衡树 明天就是一轮省选了啊。。这可能是退役前的最后一篇博文了吧(如果心情不好怕是连游记都会咕) 众周所知stl中有一个依靠红黑树实现的nb数据结构-…

    Java 2023年5月30日
    067
  • Java 字符串常量池 及 intern 方法的使用

    参考这篇文章:深入解析String#intern – 美团技术团队 (meituan.com) jdk7 版本对 intern 操作和常量池都做了一定的修改,主要包括2…

    Java 2023年5月29日
    089
  • B站 Java 精选视频(转)

    作者:微信公众号”Java研究所” 大家好,今天帮大家整理了一下b站上java相关的精华视频,供大家使用, 文末有福利!!! 尚硅谷宋红康(强力推荐) 动力…

    Java 2023年5月29日
    063
  • SpringBoot项目解决全局响应返回中文乱码问题

    一、问题 新建的基于SpringBoot的MVC项目,在请响应体中,如果有中文,会显示为乱码。 二、解决方案 1、在application.properties中设置: Origi…

    Java 2023年5月30日
    073
  • 如何使用Arthas定位问题

    在我们日常的工作中,经常会遇到一些线上才会遇到的问题。Arthas无疑是我们在工作中,定位线上问题的神奇。下面,我将介绍一下我们在工作中经常用到的一些功能。 dashboard 首…

    Java 2023年6月7日
    070
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球