ByteBuffer存在的问题

ByteBufferJDK1.4中提供的java.nio.Buffer, 在内存中预留指定大小的存储空间来存放临时数据,其他Buffer的子类有:CharBufferDoubleBufferFloatBufferIntBufferLongBuffer 和 ShortBuffer

  • ByteBuffer的长度是固定的,一旦分配完成,容量就无法动态扩容收缩,分多了会浪费内存,分少了存放大的数据时会索引越界(当传输数据大于初始化长度时,会出现BufferOverflowException索引越界的异常),所以使用ByteBuffer时,为了解决这个问题,我们一般每次put操作时,都会对可用空间进行校检,如果剩余空间不足,需要重新创建一个新的ByteBuffer,然后将旧的ByteBuffer复制到新的ByteBuffer中去
  • ByteBuffer中只有通过position获得当前可操作的位置,调用get()方法,返回ByteBuffer[postion]处的值,如果是调用put方法,将数据放入ByteBuffer[postion]的位置
  • API功能有限,部分高级功能并不支持,需开发者自己实现,且使用原生ByteBuffer较为困难(不适合小白专业户)

ByteBuf与ByteBuffer的区别

不同ByteBuf实现原理各不相同,我们先看最基本的ByteBuf与原生的ByteBuffer的区别

ByteBuf buf = Unpooled.buffer(10);
buf.writeBytes("鏖战八方QQ群391619659".getBytes());//扩容算法稍后讲解
System.out.println("Netty:" + buf);
byte[] by = new byte[buf.readableBytes()];
buf.readBytes(by);
System.out.println("Netty:" + new String(by));
System.out.println("//无耻的分割线//");ByteBuffer bf1 = ByteBuffer.allocate(100);
bf1.put("鏖战八方QQ群391619659".getBytes());
System.out.println("JDK:"+bf1);
System.out.println("当前指针:" + bf1.position());
byte[] by1 = new byte[bf1.remaining()];
System.out.println(by1.length);//What's 居然是74
bf1.get(by1);
System.out.println("未使用flip:"+new String(by1));//居然是空的
System.out.println("//无耻的分割线//");ByteBuffer bf2 = ByteBuffer.allocate(100);
bf2.put("鏖战八方QQ群391619659".getBytes());
System.out.println("JDK:"+bf2);
System.out.println("当前指针:" + bf2.position());
bf2.flip();
byte[]  by2 = new byte[bf2.remaining()];
System.out.println(by2.length);//是26了
bf2.get(by2);
System.out.println("使用flip:"+new String(by2));//拿到了

指针区别

从日志输出中可以看到,使用JDK自带的特别的麻烦,远远没有ByteBuf来的方便,无需关心读写切换指针的问题,在JDK中,由于只有一个一个position指针,我们需要通过flip()进行转换控制,而Netty却可以很好的帮我们做到扩容,它的内部维护了readerIndexwriterIndex两个指针,一开始都是0,随着数据的写入writerIndex会增加但不会超过readerIndex,当我们读取后内部会通过调用discardReadBytes来释放这部分空间,类似ByteBuffercompact方法,readerIndexwriterIndex都是可读取的,等同ByteBufferposition -> limit之间的数据,WriterIndexcapacity之间空间是可写的,等同ByteBufferlimit -> capacity

前面说到过,JDK自带的ByteBuffer无法做到自动扩容,当内容超出的时候会抛出索引越界的异常,接下来看一段代码

ByteBuf buf = Unpooled.buffer(10);
buf.writeBytes("鏖战八方QQ群391619659".getBytes());//扩容算法稍后讲解
System.out.println(buf);
System.out.println("//无耻的分割线//");
ByteBuffer buffer = ByteBuffer.allocate(10);
buffer.put("鏖战八方QQ群391619659".getBytes());
System.out.println(buffer);

问题:为什么NettyByteBuf没有报错,capacity为什么会自动扩容呢?扩容的大小是怎么计算的?

@Override
public ByteBuf writeBytes(byte[] src) {writeBytes(src, 0, src.length);return this;
}@Override
public ByteBuf writeBytes(byte[] src, int srcIndex, int length) {ensureAccessible();ensureWritable(length);setBytes(writerIndex, src, srcIndex, length);writerIndex += length;return this;
}@Override
public ByteBuf ensureWritable(int minWritableBytes) {if (minWritableBytes < 0) {throw new IllegalArgumentException(String.format("minWritableBytes: %d (expected: >= 0)", minWritableBytes));}if (minWritableBytes <= writableBytes()) {return this;}if (minWritableBytes > maxCapacity - writerIndex) {throw new IndexOutOfBoundsException(String.format("writerIndex(%d) + minWritableBytes(%d) exceeds maxCapacity(%d): %s",writerIndex, minWritableBytes, maxCapacity, this));}// 默认64     当前大小 <<= 1 翻倍int newCapacity = calculateNewCapacity(writerIndex + minWritableBytes);// Adjust to the new capacity.capacity(newCapacity);return this;
}

扩容分析

  • 调用writeBytes方法后,ByteBuf会修改writerIndex的指针大小,然后判断最小写入字节是否大于0,如果都没内容这不是在玩它么(*^▽^*)
  • 接下来是最小写入字节小于或者等于剩余容量,那就返回当前的ByteBuf,也就不会扩容了,因为能装得下
  • 接下来继续判断最小写入字节是否大于当前ByteBuf最大容量 - 已使用容量,如果最大容量都装不下说明这已经没法继续玩了,只能装这么多,扩容不了
  • 最后就是扩容处理了,Netty的做法是默认64字节,小于阀值取64,大于取64 <<= 1,成倍递增

相比其它的JAVA对象,缓冲区的分配(包括动态扩容)与释放是一个耗时操作,因此需要尽可能的复用

@Override
public ByteBuf discardReadBytes() {ensureAccessible();if (readerIndex == 0) {return this;}if (readerIndex != writerIndex) {setBytes(0, this, readerIndex, writerIndex - readerIndex);writerIndex -= readerIndex;adjustMarkers(readerIndex);readerIndex = 0;} else {adjustMarkers(readerIndex);writerIndex = readerIndex = 0;}return this;
}
public final Buffer clear() {position = 0;limit = capacity;mark = -1;return this;
}

Netty 教程 – ByteBuf详解相关推荐

  1. Netty 教程 – 解码器详解

    TCP以流的方式进行数据传输,上层的应用为了对消息进行区分,往往采用如下方式 固定消息长度,累计读取到长度和定长LEN的报文后,就认为读取到了个完整的消息,然后将计数器位置重置在读取下一个报文内容 将 ...

  2. Netty之ByteBuf详解

    1. ByteBuf的创建 在Netty中,有一个比较常见的对象ByteBuf,它其实等同于Java Nio中的ByteBuffer,但是ByteBuf对Nio中的ByteBuffer的功能做了很作增 ...

  3. netty系列之:netty中的ByteBuf详解

    文章目录 简介 ByteBuf详解 创建一个Buff 随机访问Buff 序列读写 搜索 其他衍生buffer方法 和现有JDK类型的转换 总结 简介 netty中用于进行信息承载和交流的类叫做Byte ...

  4. java 检查bytebuf长度_Java学习笔记16-Netty缓冲区ByteBuf详解

    Java学习笔记16-Netty缓冲区ByteBuf详解 Netty自己的ByteBuf ByteBuf是为解决ByteBuffer的问题和满足网络应用程序开发人员的日常需求而设计的. JDK Byt ...

  5. 支付接口教程,详解支付宝接口(二)

    支付宝的接口向来集成过程都让人觉得比较舒服,只有APP支付相对复杂,但也只是配置上复杂一些,只要清楚原理相信也不是什么难事.下面是以前介绍双钥加密原理的传送门: 支付接口教程特别篇,公钥与私钥,双钥加 ...

  6. python3.6安装教程-python3.6环境安装+pip环境配置教程图文详解

    1.python安装可以跨平台 2.有两个版本2.7和3.6,第三方库适用2.7版,两个版本不兼容 windows安装: 第一种方法官网安装: 在官网下载安装包如图: 图下点击是默认下载32位所以我们 ...

  7. python详细安装教程环境配置-python3.6环境安装+pip环境配置教程图文详解

    1.python安装可以跨平台 2.有两个版本2.7和3.6,第三方库适用2.7版,两个版本不兼容 windows安装: 第一种方法官网安装: 在官网下载安装包如图: 图下点击是默认下载32位所以我们 ...

  8. Redis数据库教程——系统详解学习Redis全过程

    Redis数据库教程--系统详解学习Redis全过程 Redis快速入门:Key-Value存储系统简介 Key-Value存储系统:     Key-Value Store是当下比较流行的话题,尤其 ...

  9. python3.6.0怎么安装pip_python3.6环境安装+pip环境配置教程图文详解

    1.python安装可以跨平台 2.有两个版本2.7和3.6,第三方库适用2.7版,两个版本不兼容 windows安装: 第一种方法官网安装: 在官网下载安装包如图: 图下点击是默认下载32位所以我们 ...

最新文章

  1. python 判断字符串是否包含另一个字符串_强烈推荐:Python字符串(string)方法整理(一)...
  2. codevs2693 上学路线(施工)
  3. 图解Oracle包实例
  4. python创建配置文件_如何写python的配置文件
  5. nacos 适配达梦、人大金仓数据库
  6. matlab中noisbloc,基于小波变换的微弱信号检测技术的研究.doc
  7. MatConvNet深度学习工具箱安装教程
  8. 【Python成长之路】python 基础篇 -- 装饰器【华为云分享】
  9. Windows程序设计_19_测试Windows应用程序加载函数
  10. 在c语言程序中整型常量不能表示的数制是,C源程序中不能表示的数制有哪些
  11. 自定义MyBatis拦截器
  12. 电脑课学生端密码查看
  13. 广袤之中:沿着克拉克三大定律,读懂华为的最深期待
  14. 传感器技术-光电式传感器(学习笔记十)
  15. 通过比赛整理出的8条Numpy实用技巧【你知道如何频数统计和按某列进行排序么?】...
  16. vue调倍速后声音变了_pr加速人声后声音变调失真怎么办?
  17. 用Python控制摄像头拍照并发邮件
  18. 机电照明工程软件测试大纲,2019最新大纲 | 公路水运工程试验检测考试大纲《交通工程》...
  19. [模块加载失败:找不到指定的模块]——如何解决DLL加载问题?
  20. SPICE的器件模型

热门文章

  1. CAD制图软件使用心得(第五期)
  2. 华为软件研发面试题2 .
  3. vue3 vscode插件volar配置
  4. java poi生成word 插入表格,图片,自动合并单元格,并且可以在已存在的word上追加
  5. Autodesk 3ds Max 2017 中文正确注册的姿势
  6. python游戏csgo开挂_使用Python实现CSGO皮肤磨损查询
  7. 公有云+5G核心网,狼真的来了吗?
  8. 估计IMU和车辆之间的安装角度
  9. java人员的工龄_计算员工工龄,这个问题千万要注意
  10. 高通骁龙820A车用处理器全面解读