java 检查bytebuf长度_Java学习笔记16-Netty缓冲区ByteBuf详解
Java学习笔记16-Netty缓冲区ByteBuf详解
Netty自己的ByteBuf
ByteBuf是为解决ByteBuffer的问题和满足网络应用程序开发人员的日常需求而设计的。
JDK ByteBuffer的缺点:
无法动态扩容:长度是固定的,不能动态扩展和收缩,当数据大于ByteBuffer容量时,会发生索引越界异常。
API使用复杂:读写的时候需要手工调用flip()和rewind()等方法,使用时需要非常谨慎的使用这些api,否则很容易出现错误。
ByteBuf做了哪些增强:
API操作便捷性
动态扩容
多种ByteBuf实现
高效的零拷贝机制
ByteBuf操作
ByteBuf三个重要属性:readerIndex读取位置、writerIndex写入位置、capacity容量
提供了两个指针变量来支持顺序读和写操作,分别是readerIndex和writerIndex
常用方法定义
随机访问索引 getByte
顺序读 read*
顺序写 write*
清除已读内容 discardReadBytes
清除缓冲区 clear
搜索操作
标记和重置
引用计数和释放
discardable bytes
readable bytes
writable bytes
已读可丢弃区域
可读区域
待写区域
0<= readerIndex
<= writerIndex
<= capacity
ByteBuf动态扩容
capacity默认值:256字节;最大值:Integer.MAX_VALUE(2GB)
write*方法调用时,通过AbstractByteBuf.ensureWritable0进行检查。
容量计算方法:AbstractByteBufAllocator.calculateNewCapacity(新capacity的最小要求,capacity最大值)
根据新capacity的最小值要求,对应有两套计算方法:
没超过4M:从64字节开始,每次增加1倍,直至计算出来的newCapacity满足新容量的最小要求。
示例:当前大小256,已写250,继续写10字节数据,需要的容量最小要求是261,则新容量是64*2*2*2=512
超过4M:新容量 = 新容量最小要求 / 4M * 4M +4M
示例:当前大小3M,已写3M,继续写2M数据,需要的容量最小要求是5M,则新容量是9M(不能超过最大值)。
4M的来源:一个固定的阀值AbstractByteBufAllocator.CALCULATE_THRESHOLD
选择合适的ByteBuf实现
了解核心的:3个纬度的划分方式,8种具体实现
堆内/堆外
是否池化
访问方式
具体实现类
备注
unpool
safe
UnpooledHeapByteBuf
数组实现
heap堆内
unsafe
UnpooledUnsafeHeapByteBuf
Unsafe类直接操作内存
pool
safe
PooledHeapByteBuf
~
unsafe
PooledUnsafeHeapByteBuf
~
unpool
safe
UnpooledDirectByteBuf
NIO DirectByteBuffer
direct堆外
unsafe
UnpooledUnsafeDirectByteBuf
~
pool
safe
PooledDirectByteBuf
~
unsafe
PooledUnsafeDirectByteBuf
~
在使用中,都是通过ByteBufAllocator分配器进行申请,同时分配器具备有内存管理的功能
Unsafe的实现
unsafe意味着不安全的操作。但是更底层的操作会带来性能的提升和特殊功能,Netty中会尽力使用unsafe。
Java语言很重要的特性是“一次编写到处运行”,所以它针对底层的内存或者其他操作,做了很多封装。
而unsafe提供了一系列我们操作底层的方法,可能会导致不兼容或者不可知的异常。
Info.仅返回一些低级的内存信息
Objects.提供用于操作对象及其字段的方法
Classes.提供用于操作类及其静态字段的方法
addressSize
allocateInstance
staticFieldOffset
pageSize
objectFieldOffset
defineClass
defineAnonymousClass
ensureClassInitialized
Synchronization.低级的同步原语
Memory.直接访问内存方法
Arrays.操作数组
monitorEnter
allocateMemory
arrayBaseOffset
tryMonitorEnter
copyMemory
arrayIndexScale
monitorExit
freeMemory
compareAndSwapInt
getAddress
putOrderedInt
getInt
putInt
PooledByteBuf对象、内存复用
PoolThreadCache:PooledByteBufAllocator实例维护的一个线程变量。
多种分类的MemoryRegionCache数组用作内存缓存,MemoryRegionCache内部是链表,队列里面存Chunk。
PoolChunk里面维护了内存引用,内存复用的做法就是把buf的memory指向chunk的memory。
PooledByteBufAllocator.ioBuffer运作过程梳理:
EventLoop - Thread --allocate--> Arena(负责buf分配管理) -->
创建或复用ByteBuf对象
PooledByteBuf
stack
RECYCLER ---->
buffer
cache
尝试从对应的缓存 复用内存空间
PoolThreadCache
TINY_MR_CACHE * 32 Q[512]
SMALL_MR_CACHE * 4 Q[256]
NORMAL_MR_CACHE * 3 Q[64]
无缓存时,从内存中申请 直接向内存申请 unpool
零拷贝机制
Netty的零拷贝机制,是一种应用层的实现。和底层JVM、操作系统内存机制并无过多关联。
CompositeByteBuf,将多个ByteBuf合并为一个逻辑上的ByteBuf,避免了各个ByteBuf之间的拷贝。
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
ByteBuf newBuffer = compositeByteBuf.addComponents(true, buffer1, buffer2);
wrappedBuffer()方法,将byte[]数组包装成ByteBuf对象。
ByteBuf newBuffer = Unpooled.wrappedBuffer(new byte[]{1, 2, 3, 4, 5});
slice()方法。将一个ByteBuf对象切分成多个ByteBuf对象。
ByteBuf buffer1 = Unpooled.wrappedBuffer("hello".getBytes());
ByteBuf newBuffer = buffer1.slice(1, 2);
ByteBuf测试代码
import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
import java.util.Arrays;
/**
* @Author: Wenx
* @Description:
* @Date: Created in 2019/11/25 22:31
* @Modified By:
*/
public class ByteBufDemo {
public static void main(String[] args) {
apiTest();
compositeTest();
wrapTest();
sliceTest();
}
public static void apiTest() {
// +-------------------+------------------+------------------+
// | discardable bytes | readable bytes | writable bytes |
// | | (CONTENT) | |
// +-------------------+------------------+------------------+
// | | | |
// 0 <= readerIndex <= writerIndex <= capacity
// 1.创建一个非池化的ByteBuf,大小为10个字节
ByteBuf buf = Unpooled.buffer(10);
//ByteBuf buf = Unpooled.directBuffer(10);
println("1.原始ByteBuf为", buf);
// 2.写入一段内容
byte[] bytes = {1, 2, 3, 4, 5};
buf.writeBytes(bytes);
print("2.写入的bytes为", bytes);
println("写入内容后ByteBuf为", buf);
// 3.读取一段内容
byte b1 = buf.readByte();
byte b2 = buf.readByte();
print("3.读取的bytes为", new byte[]{b1, b2});
println("读取内容后ByteBuf为", buf);
// 4.将读取的内容丢弃
buf.discardReadBytes();
println("4.将读取的内容丢弃后ByteBuf为", buf);
// 5.清空读写指针
buf.clear();
println("5.清空读写指针后ByteBuf为", buf);
// 6.再次写入一段内容,比第一段内容少
byte[] bytes2 = {1, 2, 3};
buf.writeBytes(bytes2);
print("6.写入的bytes为", bytes2);
println("写入内容后ByteBuf为", buf);
// 7.将ByteBuf清零
buf.setZero(0, buf.capacity());
println("7.将内容清零后ByteBuf为", buf);
// 8.再次写入一段超过容量的内容
byte[] bytes3 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
buf.writeBytes(bytes3);
print("8.写入的bytes为", bytes3);
println("写入内容后ByteBuf为", buf);
// 随机访问索引 getByte
// 顺序读 read*
// 顺序写 write*
// 清除已读内容 discardReadBytes
// 清除缓冲区 clear
// 搜索操作
// 标记和重置
// 完整代码示例:参考
// 搜索操作 读取指定位置 buf.getByte(1);
}
public static void compositeTest() {
ByteBuf buffer1 = Unpooled.buffer(3);
buffer1.writeByte(1);
ByteBuf buffer2 = Unpooled.buffer(3);
buffer2.writeByte(4);
print("buffer1为", buffer1);
print("buffer2为", buffer2);
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
ByteBuf newBuffer = compositeByteBuf.addComponents(true, buffer1, buffer2);
println("CompositeByteBuf为", newBuffer);
}
public static void wrapTest() {
byte[] arr = {1, 2, 3, 4, 5};
ByteBuf newBuffer = Unpooled.wrappedBuffer(arr);
print("byte[]为", arr);
print("wrappedBuffer为", newBuffer);
print("newBuffer.getByte(4)为", newBuffer.getByte(4));
arr[4] = 6;
println("byte[4] = 6; 后newBuffer.getByte(4)为", newBuffer.getByte(4));
}
public static void sliceTest() {
ByteBuf oldBuffer = Unpooled.wrappedBuffer("hello".getBytes());
ByteBuf newBuffer = oldBuffer.slice(1, 2);
print("oldBuffer为", oldBuffer);
print("oldBuffer.slice(1, 2); 为", newBuffer);
print("newBuffer.getByte(0)为", newBuffer.getByte(0));
print("newBuffer.getByte(1)为", newBuffer.getByte(1));
// 新buf中原buf的引用
ByteBuf buf = newBuffer.unwrap();
print("newBuffer.unwrap()为", buf);
print("buf.getByte(0)为", buf.getByte(0));
print("buf.getByte(1)为", buf.getByte(1));
print("buf.getByte(2)为", buf.getByte(2));
print("buf.getByte(3)为", buf.getByte(3));
print("buf.getByte(4)为", buf.getByte(4));
}
private static void print(String str, byte b) {
System.out.println(String.format("%s==========>%s", str, b));
}
private static void print(String str, byte[] bytes) {
System.out.println(String.format("%s==========>%s", str, Arrays.toString(bytes)));
}
private static void print(String str, ByteBuf buf) {
print(str, buf, "");
}
private static void print(String before, ByteBuf buf, String after) {
byte[] bytes;
if (buf.hasArray()) {
bytes = buf.array();
} else {
int capacity = buf.capacity();
bytes = new byte[capacity];
for (int i = 0; i < buf.capacity(); i++) {
bytes[i] = buf.getByte(i);
}
}
System.out.println(String.format("%s==========>%s(ridx:%s, widx: %s, cap: %s)%s", before, Arrays.toString(bytes), buf.readerIndex(), buf.writerIndex(), buf.capacity(), after));
}
private static void println(String str, byte b) {
System.out.println(String.format("%s==========>%s
", str, b));
}
private static void println(String str, ByteBuf buf) {
print(str, buf, "
");
}
}
java 检查bytebuf长度_Java学习笔记16-Netty缓冲区ByteBuf详解相关推荐
- 小猫爪:i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解
i.MX RT1050学习笔记26-RT1xxx系列的FlexCAN详解 1 前言 2 FlexCAN简介 2.1 MB(邮箱)系统 2.1.1 正常模式下 2.1.2 激活了CAN FD情况下 2. ...
- IP地址和子网划分学习笔记之《IP地址详解》
在学习IP地址和子网划分前,必须对进制计数有一定了解,尤其是二进制和十进制之间的相互转换,对于我们掌握IP地址和子网的划分非常有帮助,可参看如下目录详文. IP地址和子网划分学习笔记相关篇章: 1.I ...
- IP地址和子网划分学习笔记之《子网划分详解》
一,子网划分概述 IP地址和子网划分学习笔记相关篇章: 1.IP地址和子网划分学习笔记之<预备知识:进制计数> 2.IP地址和子网划分学习笔记之<IP地址详解> 3.IP地址和 ...
- JDBC学习笔记02【ResultSet类详解、JDBC登录案例练习、PreparedStatement类详解】
黑马程序员-JDBC文档(腾讯微云)JDBC笔记.pdf:https://share.weiyun.com/Kxy7LmRm JDBC学习笔记01[JDBC快速入门.JDBC各个类详解.JDBC之CR ...
- 我的学习笔记——CSS背景渐变(Gradients)详解
我的学习笔记--CSS背景渐变(Gradients)详解 一.线性渐变(Linear Gradients) 1.语法 background-image: linear-gradient(directi ...
- java基本语法心得_Java学习笔记(一)——基础语法(上)
Java学习笔记(一)--基础语法(上) 软件构造 写在前面 编写Java程序时,应注意以下几点:大小写敏感:Java是大小写敏感的,这就意味着标识符Hello与hello是不同的. 类名:对于所有的 ...
- redis学习笔记(2)之redis主从详解
redis主从详解 主从详解 主从配置 拓扑 原理 数据同步 概念 复制偏移量 复制积压缓冲区 主节点运行ID Psync命令 全量复制流程 部分复制流程 心跳 缓冲大小调节 读写分离 内容来源为六星 ...
- Apollo星火计划学习笔记——Apollo决策规划技术详解及实现(以交通灯场景检测为例)
文章目录 前言 1. Apollo决策技术详解 1.1 Planing模块运行机制 1.2 Apollo决策功能的设计与实现 1.2.1参考路径 Reference Line 1.2.2 交规决策 T ...
- 学习笔记——Maven pom.xml配置详解
POM的全称是"ProjectObjectModel(项目对象模型)". pom.xml详解 声明规范 <projectxmlns="http://maven.ap ...
最新文章
- 深挖数据价值 阿里云栖开年大会报道
- discuz 二次开发文章
- SharpStrike:基于C#实现的后渗透漏洞利用工具
- Markdown:数学公式(4)
- 去除VScode中的黄色警告波浪线问题
- iis自带的ftp服务器权限设置方法,IIS ftp 权限控制
- 新手篇 | K8S配置最佳实践
- 辽宁移动客服呼叫中心两级质检管理效果佳
- WebStorm 汉化教程-Mac
- 知识图谱嵌入:TransE算法原理及代码详解
- 小米笔记本UEFI关闭安全启动
- DN值,辐射率(Radiance),反射率
- 总资产周转率、资产负债率、销售净利率、资产收益率、净资产利润率、劳动生产率、人均利润率
- 魔兽争霸3 the oracle,疯狂SQL之魔兽争霸
- GD32W515实现NES模拟器
- Syntax Error Error No ESLint configuration found in statusGitmibsrc
- 微信图文素材中图片url替换
- Camtasia Studio 8
- 微信开发者工具控制台空白问题解决方案
- 工厂方法模式-----女娃造人的故事
热门文章
- 面试中常问的List去重问题,你都答对了吗?
- 20175213 2018-2019-2 《Java程序设计》第6周学习总结
- silverlight,WPF动画终极攻略之番外 3D切换导航篇(Blend 4开发)
- python列表操作
- 前端编码风格规范(3)—— JavaScript 规范
- 【转】一个优秀的Javascript框架--Prototype解说
- Promise.all捕获错误
- python如何创建模块教程_Python创建模块及模块导入的方法
- Java黑皮书课后题第5章:*5.16(找出一个整数的因子)编写程序,读入一个整数,然后以升序显示它的所有最小因子。例如,若输入的整数是120,那么输出就应该是:2、2、2、3、5
- 课堂派派典型用户和场景