前言:

最近在学习 netty,看了 Netty 权威指南,其中源码第一篇就讲到了 ByteBuffer 和 byteBuf 的区别,这里就总结一下。

ByteBuffer

bytebuffer 是 Java NIO 里面提供的字节容器。有一个指针用于处理读写操作,每次读写的时候都需要调用 flip()或是 clear()方法,不然将会报异常。

部分源码:

public abstract class ByteBuffer  extends Buffer{

}

public abstract class Buffer {

// Invariants: mark <= position <= limit <= capacity

private int mark = -1;

private int position = 0;

private int limit;

private int capacity;

}

成员变量关系

属性

描述

mark

调用 mark()方法的话,mark 值将存储当前 position 的值,等下次调用 reset()方法时,会设定 position 的值为之前的标记值

position

用来表示 bytes 的容量,那么可以想像 capacity 就等于 bytes.size(),此值在初始化 bytes 后,是不可变的

limit

用来表示 bytes 实际装了多少数据,可以容易想像得到 limit <= capacity,此值是可灵活变动的

capacity

用来表示在哪个位置开始往 bytes 写数据或是读数据,此值是可灵活变动的

他们之间的关系:mark <= position <= limit <= capacity

创建一个 bytebuffer

ByteBuffer bf = ByteBuffer.allocate(10);

position,limit 和 capacity 图解如下:

「写入数据到 bytebuffer」

bf.put((byte)’H’)

.put((byte)’e’)

.put((byte)’l’)

.put((byte)’l’)

.put((byte)’o’)

在操作 bytebuffer 的时候,每次往里面写入一个 byte,position 则会后移一位。

「使用 flip() 刷新缓冲区为 读模式」

bf.flip()

bytebuffer 有两种模式,分别是写模式和读模式,这两种模式通过使用 flip 方法进行模式。

如上将缓冲区切换为读模式,则 position 变成了初值位置 0,而 limit 变成了写模式下 position 位置。

「读取数据」

bf.get()

调用 get()获取缓冲区中的一个 byte。

「清除缓冲区」

bf.clear()

tips: 这个方法简单理解就是复位(Reset) 但不会清除数据(position=0, limit=capacity)

JDK 自带的 ByteBuffer 并不足够完美,它有以下缺陷:

摘抄自《Netty 权威指南》

ByteBuffer 长度固定,一旦分配完成,它的容量不能动态扩展和收缩,当需要编码的 POJO 对象大于 ByteBuffer 的容量时,会发生索引越界异常;

ByteBuffer 只有一个标识位控的指针 position,读写的时候需要手工调用 flip()和 rewind()等,使用者必须小心谨慎地处理这些 API,否则很容易导致程序处理失败;

ByteBuffer 的 API 功能有限,一些高级和实用的特性它不支持,需要使用者自己编程实现。

ByteBuf

bytebuf 是 Netty 里的封装的数据缓存区,区别于 bytebuffer 里需要 position、limit、capacity 等属性来操作 bytebuffer 数据读写,而 bytebuf 里面则是通过 两个指针协助缓存区的读写操作,分别为 readIndex 和 writerIndex 。

在创建 bytebuf 的时候,readIndex 和 writerIndex 的值都是 0,但随着有数据被写入 writerIndex 会增加,读取数据的时候 readIndex 也会增加, 但是 readIndex 不会超过 writerIndex。

图解:

创建一个 bytebuf

ByteBuf bf= Unpooled.buffer(10,100)

write:写入 N 个字节之后 ByteBuf

read:读取 M 个字节后(M

使用 demo:

ByteBuf bf= Unpooled.buffer(10,100);

bf.writeBoolean(true);

bf.writeInt(666);

bf.writeInt(777);

bf.writeInt(888);

System.out.println(bf.readBoolean());

System.out.println(bf.readInt());

System.out.println(bf.readInt());

System.out.println(bf);

ByteBuf 的基本分类:

AbstractByteBuf 之下有众多子类,大致可以从三个维度来进行分类,分别如下:

「Pooled」:池化内存,就是从预先分配好的内存空间中提取一段连续内存封装成一个ByteBuf 分给应用程序使用。

「Unsafe」:是JDK 底层的一个负责IO 操作的对象,可以直接拿到对象的内存地址,基于内存地址进行读写操作。

「Direct」:堆外内存,是直接调用JDK 的底层API 进行物理内存分配,不在JVM 的堆内存中,需要手动释放。

ByteBuf 最基本的读写API 操作在AbstractByteBuf 中已经实现了,其众多子类采用不同的策略来分配内存空间,下面对重要的几个子类总结如下:

PooledHeapByteBuf :池化的堆内缓冲区

PooledUnsafeHeapByteBuf :池化的Unsafe 堆内缓冲区

PooledDirectByteBuf :池化的直接(堆外)缓冲区

PooledUnsafeDirectByteBuf :池化的Unsafe 直接(堆外)缓冲区

UnpooledHeapByteBuf :非池化的堆内缓冲区

UnpooledUnsafeHeapByteBuf :非池化的Unsafe 堆内缓冲区

UnpooledDirectByteBuf :非池化的直接(堆外)缓冲区

UnpooledUnsafeDirectByteBuf :非池化的Unsafe 直接(堆外)缓冲区

ByteBuffer 和 ByteBuf 的区别

Netty 的 ByteBuf 采用了读写索引分离的策略(readerIndex 与 writerIndex),一个初始化(里面尚未有任何数据)的 ByteBuf 的 readerIndex 与 writerIndex 值都为 0

当读索引与写索引处于同一个位置时,如果继续读取,那么就会抛出 IndexOutOfBoundsException。

ByteBuffer 只有一个标识位置的指针,读写的时候需要手动的调用 flip()和 rewind()等,否则很容易导致程序处理失败。而 ByteBuf 有两个标识位置的指针,一个写 writerIndex,一个读 readerIndex,读写的时候不需要调用额外的方法。

ByteBuffer 必须自己长度固定,一旦分配完成,它的容量不能动态扩展和收缩;ByteBuf 默认容器大小为 256,支持动态扩容,在允许的最大扩容范围内(Integer.MAX_VALUE)。

NIO 的 SocketChannel 进行网络读写时,操作的对象是 JDK 标准的 java.nio.byteBuffer。由于 Netty 使用统一的 ByteBuf 替代 JDK 原生的 java.nio.ByteBuffer,所以 ByteBuf 中定义了 ByteBuffer nioBuffer()方法将 ByteBuf 转换成 ByteBuffer。

bytebuffer长度_图解ByteBuffer和ByteBuf相关推荐

  1. 顺序表中有效元素的长度_图解线性表,启动数据结构的大门,深刻理解链式存储和顺序存储!...

    数据结构之线性表 前言 ❝ 提到数据结构,可能会有很多人马上联想到栈,队列,树,哈希表,图等各种经常提到的数据结构,但是我们去忽略了本质,这些都是抽象的逻辑结构,追本溯源,数据结构中的存储方式只有两种 ...

  2. bytebuffer转图片_ByteBuffer: 图解ByteBuffer(转)

    ByteBuffer前前后后看过好几次了,实际使用也用了一些,总觉得条理不够清晰. <程序员的思维修炼>一本书讲过,主动学习,要比单纯看资料效果来的好,所以干脆写个详细点的文章来记录一下. ...

  3. Java NIO学习笔记之图解ByteBuffer

    转载自 Java NIO学习笔记之图解ByteBuffer ByteBuffer前前后后看过好几次了,实际使用也用了一些,总觉得条理不够清晰. <程序员的思维修炼>一本书讲过,主动学习,要 ...

  4. AIO系列文档(1)----图解ByteBuffer

    因何而写 网上关于bytebuffer的文章真的很多,为何在此还要写一篇呢?主要是基于以下几点考虑 很多人在使用t-io时,还不会bytebuffer,只会照着t-io提供的例子照猫画虎,不利于灵活运 ...

  5. java bytebuffer分包收集,Java ByteBuffer rewind()用法及代码示例

    java.nio.ByteBuffer类的rewind()方法用于倒带此缓冲区.位置设置为零,标记被丢弃.假设已正确设置了限制,请在序列channel-write或get操作之前调用此方法.调用此方法 ...

  6. hbase 2.4 java.lang.NoSuchMethodError: java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer

    hbase 2.4集群环境启动报错,java.lang.NoSuchMethodError: java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer ​ 详细 ...

  7. bytebuffer长度_ByteBuffer常用方法详解

    缓冲区(Buffer)就是在内存中预留指定大小的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区: 使用缓冲区有这么两个好处: 1.减少实际的物理读写次数 2.缓冲 ...

  8. java 检查bytebuf长度_Netty实战五之ByteBuf

    网络数据的基本单位总是字节,Java NIO 提供了ByteBuffer作为它的字节容器,但是其过于复杂且繁琐. Netty的ByteBuffer替代品是ByteBuf,一个强大的实现,即解决了JDK ...

  9. 正则表达式限定长度_自己写一个通用的邮箱正则表达式

    今天把正则又复习了一遍,为了加深记忆,自己写一个邮箱的正则表达式 咱们先来看几个合法的邮箱地址 hd33322@nat123.com maksim.kim.82@d-link.ua vova_laza ...

最新文章

  1. Java实用教程笔记 接口与实现
  2. 人耳识别代码_语音识别之——音频特征fbank与mfcc,代码实现与分析
  3. import lombok 报错_Android上使用Lombok和set、get方法告别
  4. 黑苹果intel网卡驱动方法
  5. android 美拍加表情,怎么把美拍加表情
  6. 数据库连接池——基本原理
  7. 从底层谈webgis原理设计与实现(二)探究本质,WebGIS前端地图显示之地图比例尺换算原理...
  8. 6-3近期工作总结、下一步工作安排及技术知识
  9. 手机指北针 + Python绘制徒步路线图
  10. 声速的测量数据处理代码
  11. 微信小程序----第二天(小程序 - 模板与配置)
  12. supervisor 使用
  13. 剧情/惊悚基因危机:天才科学家的五日
  14. 【LeetCode】871. Minimum Number of Refueling Stops 解题报告(Python)
  15. python 播放本地音乐_python本地音乐播放器
  16. 以外卖餐饮大数据为例 量身打造数据化运营体系
  17. Android学习之ContentProvider
  18. MA35D1记录1-源码编译
  19. 最优化理论——可行方向法
  20. 杰特康机器人的概述_工业机器人概述

热门文章

  1. Python基础的学习和简单爬虫的编写
  2. 各大新生的军训马上快结束了!Python告诉你军训前后你黑了几度!
  3. Framework7 框架简介
  4. 类似直播飘星动画效果
  5. WebSocket——vue3简易聊天室
  6. [区块链笔记9] 区块链相关概念
  7. 郑州网站域名升级https通配符证书
  8. vue中使用axios
  9. 两月从2钻升至4钻的淘宝直播心得!
  10. php execl 乱码,phpexcel乱码