当前位置: 首页 > news >正文

深圳网站建设新闻拍摄广告片制作公司

深圳网站建设新闻,拍摄广告片制作公司,静态中英文网站怎么做,上海新闻最新消息今天highlight: arduino-light ByteBuf 是 Netty 的数据容器#xff0c;所有网络通信中字节流的传输都是通过 ByteBuf 完成的。 然而 JDK NIO 包中已经提供了类似的 ByteBuffer 类#xff0c;为什么 Netty 还要去重复造轮子呢#xff1f;本节课我会详细地讲解 ByteBuf。 JDK NIO… highlight: arduino-light ByteBuf 是 Netty 的数据容器所有网络通信中字节流的传输都是通过 ByteBuf 完成的。 然而 JDK NIO 包中已经提供了类似的 ByteBuffer 类为什么 Netty 还要去重复造轮子呢本节课我会详细地讲解 ByteBuf。 JDK NIO的ByteBuffer 我们首先介绍下 JDK NIO 的 ByteBuffer才能知道 ByteBuffer 有哪些缺陷和痛点。下图展示了 ByteBuffer 的内部结构 从图中可知ByteBuffer 包含以下四个基本属性 mark为某个读取过的关键位置做标记方便回退到该位置position当前读取的位置limitbuffer 中有效的数据长度大小capacity初始化时的空间容量。 以上四个基本属性的关系是mark position limit capacity。结合 ByteBuffer 的基本属性不难理解它在使用上的一些缺陷。 第一ByteBuffer 分配的长度是固定的无法动态扩缩容所以很难控制需要分配多大的容量。如果分配太大容量容易造成内存浪费如果分配太小存放太大的数据会抛出 BufferOverflowException 异常。在使用 ByteBuffer 时为了避免容量不足问题你必须每次在存放数据的时候对容量大小做校验如果超出 ByteBuffer 最大容量那么需要重新开辟一个更大容量的 ByteBuffer将已有的数据迁移过去。整个过程相对烦琐对开发者而言是非常不友好的。 第二ByteBuffer 只能通过 position 获取当前可操作的位置因为读写共用的 position 指针所以需要频繁调用 flip、rewind 方法切换读写状态开发者必须很小心处理 ByteBuffer 的数据读写稍不留意就会出错。 ByteBuffer 作为网络通信中高频使用的数据载体显然不能够满足 Netty 的需求Netty 重新实现了一个性能更高、易用性更强的 ByteBuf相比于 ByteBuffer 它提供了很多非常酷的特性 容量可以按需动态扩展类似于 StringBuffer读写采用了不同的指针读写模式可以随意切换不需要调用 flip 方法通过内置的复合缓冲类型可以实现零拷贝支持引用计数支持缓存池。 这里我们只是对 ByteBuf 有一个简单的了解接下来我们就一起看下 ByteBuf 是如何实现的吧。 痛点: 1.readIndex 和 writeIndex没有分开 2.需要调用flip和clear方法 3.api命名区分度低 Netty ByteBuf 内部结构 同样我们看下 ByteBuf 的内部结构与 ByteBuffer 做一个对比。 从图中可以看出ByteBuf 包含三个指针读指针 readerIndex、写指针 writeIndex、最大容量 maxCapacity根据指针的位置又可以将 ByteBuf 内部结构可以分为四个部分 第一部分是废弃字节表示已经丢弃的无效字节数据。 第二部分是可读字节表示 ByteBuf 中可以被读取的字节内容可以通过 writeIndex - readerIndex 计算得出。从 ByteBuf 读取 N 个字节readerIndex 就会自增 NreaderIndex 不会大于 writeIndex当 readerIndex writeIndex 时表示 ByteBuf 已经不可读。 第三部分是可写字节向 ByteBuf 中写入数据都会存储到可写字节区域。向 ByteBuf 写入 N 字节数据writeIndex 就会自增 N当 writeIndex 超过 capacity表示 ByteBuf 容量不足需要扩容。 第四部分是可扩容字节表示 ByteBuf 最多还可以扩容多少字节当 writeIndex 超过 capacity 时会触发 ByteBuf 扩容最多扩容到 maxCapacity 为止超过 maxCapacity 再写入就会出错。 由此可见Netty 重新设计的 ByteBuf 有效地区分了可读、可写以及可扩容数据解决了 ByteBuffer 无法扩容以及读写模式切换烦琐的缺陷。 接下来我们一起学习下 ByteBuf 的核心 API你可以把它当作 ByteBuffer 的替代品单独使用。 引用计数 ByteBuf 是基于引用计数设计的它实现了 ReferenceCounted 接口ByteBuf 的生命周期是由引用计数所管理。 只要引用计数大于 0表示 ByteBuf 还在被使用 当 ByteBuf 不再被其他对象所引用时引用计数为 0那么代表该对象可以被释放。 当新创建一个 ByteBuf 对象时它的初始引用计数为 1当 ByteBuf 调用 release() 后引用计数减 1。 所以不要误以为调用了 release() 就会保证 ByteBuf 对象一定会被回收。因为可能计数是2。 你可以结合以下的代码示例做验证 md ByteBuf buffer ctx.alloc().directBuffer(); assert buffer.refCnt() 1; buffer.release(); assert buffer.refCnt() 0; 引用计数对于 Netty 设计缓存池化有非常大的帮助当引用计数为 0该 ByteBuf 可以被放入到对象池中避免每次使用 ByteBuf 都重复创建对于实现高性能的内存管理有着很大的意义。 此外 Netty 可以利用引用计数的特点实现内存泄漏检测工具。 JVM 并不知道 Netty 的引用计数是如何实现的当 ByteBuf 对象不可达时一样会被 GC 回收掉但是如果此时 ByteBuf 的引用计数不为 0那么该对象就不会释放或者被放入对象池从而发生了内存泄漏。 Netty 会对分配的 ByteBuf 进行抽样分析检测 ByteBuf 是否已经不可达且引用计数大于 0判定内存泄漏的位置并输出到日志中你需要关注日志中 LEAK 关键字。 ByteBuf 分类 ByteBuf 有多种实现类每种都有不同的特性下图是 ByteBuf 的家族图谱可以划分为三个不同的维度Heap/Direct、Pooled/Unpooled和Unsafe/非 Unsafe我逐一介绍这三个维度的不同特性。 Heap/Direct Heap/Direct 就是堆内和堆外内存。 Heap 指的是在 JVM 堆内分配底层依赖的是字节数据 Direct 则是堆外内存不受 JVM 限制分配方式依赖 JDK 底层的 ByteBuffer。 Pooled/Unpooled Pooled/Unpooled 表示池化还是非池化内存。 Pooled 是从预先分配好的内存中取出使用完可以放回 ByteBuf 内存池等待下一次分配。 而 Unpooled 是直接调用系统 API 去申请内存确保能够被 JVM GC 管理回收。 Unsafe/非 Unsafe Unsafe/非 Unsafe 的区别在于操作方式是否安全。 Unsafe 表示每次调用 JDK 的 Unsafe 对象操作物理内存依赖 offset index 的方式操作数据。 非 Unsafe 则不需要依赖 JDK 的 Unsafe 对象直接通过数组下标的方式操作数据。 ByteBuf 核心 API 我会分为指针操作、数据读写和内存管理三个方面介绍 ByteBuf 的核心 API。在开始讲解 API 的使用方法之前先回顾下之前我们实现的自定义解码器以便于加深对 ByteBuf API 的理解。 java public final void decode(ChannelHandlerContext ctx, ByteBuf in, ListObject out) { // 判断 ByteBuf 可读取字节 if (in.readableBytes() 14) { return; } in.markReaderIndex(); // 标记 ByteBuf 读指针位置 in.skipBytes(2); // 跳过魔数 in.skipBytes(1); // 跳过协议版本号 //获取序列化方式 byte serializeType in.readByte(); in.skipBytes(1); // 跳过报文类型 in.skipBytes(1); // 跳过状态字段 in.skipBytes(4); // 跳过保留字段 //获取数据长度 int dataLength in.readInt(); if (in.readableBytes() dataLength) { in.resetReaderIndex(); // 重置 ByteBuf 读指针位置 return; } //根据数据长度构造 byte[] byte[] data new byte[dataLength]; in.readBytes(data); //根据序列化方式 反序列化 SerializeService serializeService getSerializeServiceByType(serializeType); //反序列化为对象 Object obj serializeService.deserialize(data); if (obj ! null) { out.add(obj); } } 指针操作 API readerIndex() readerIndex() 返回的是当前的读指针的 readerIndex 位置 writeIndex() writeIndex() 返回的当前写指针 writeIndex 位置。 markReaderIndex() markReaderIndex() 用于保存当前readerIndex 的位置。 resetReaderIndex() resetReaderIndex() 则将当前 readerIndex 重置为之前markReaderIndex保存的位置。 markReaderIndex和resetReaderIndex这对 API 在实现协议解码时最为常用例如在上述自定义解码器的源码中在读取协议内容长度字段之前先使用 markReaderIndex() 保存了 readerIndex 的位置如果 ByteBuf 中可读字节数小于长度字段的值则表示 ByteBuf 还没有一个完整的数据包此时直接使用 resetReaderIndex() 重置readerIndex 的位置。 此外对应的写指针操作还有 markWriterIndex() 和 resetWriterIndex()与读指针的操作类似我就不再一一赘述了。 数据读写 API isReadable() isReadable() 用于判断 ByteBuf 是否可读如果 writerIndex 大于 readerIndex那么 ByteBuf 是可读的否则是不可读状态。 readableBytes() readableBytes() 可以获取 ByteBuf 当前可读取的字节数可以通过 writerIndex - readerIndex 计算得到 readBytes(byte[] dst) writeBytes(byte[] src) readBytes() 和 writeBytes() 是两个最为常用的方法。 readBytes() 是将 ByteBuf 的数据读取相应的字节到字节数组dst 中,readBytes() 经常结合 readableBytes() 一起使用 dst 字节数组的大小通常等于 readableBytes() 的大小。 java //收到的消息 ByteBuf bytebuf (ByteBuf) msg; //构建字节数组 byte[] req new byte[bytebuf.readableBytes()]; //将ByteBuf中的数据读取到字节数组中 bytebuf.readBytes(req); String body new String(req, UTF-8); readByte() writeByte(int value) readByte() 是从 ByteBuf 中读取一个字节相应的 readerIndex 1同理 writeByte 是向 ByteBuf 写入一个字节相应的 writerIndex 1。 类似的 Netty 提供了 8 种基础数据类型的读取和写入例如 readChar()、readShort()、readInt()、readLong()、writeChar()、writeShort()、writeInt()、writeLong() 等在这里就不详细展开了。 getByte(int index) setByte(int index, int value) readByte() 是从 ByteBuf 中读取一个字节相应的 readerIndex 1 同理 writeByte 是向 ByteBuf 写入一个字节相应的 writerIndex 1。 与 readByte() 和 writeByte() 相对应的还有 getByte() 和 setByte()get/set 系列方法也提供了 8 种基础类型的读写那么这两个系列的方法有什么区别呢 read/write 方法在读写时会改变readerIndex 和 writerIndex 指针而 get/set 方法则不会改变指针位置。 release() retain() 之前已经介绍了引用计数的基本概念每调用一次 release() 引用计数减 1每调用一次 retain() 引用计数加 1。 slice() 返回ByteBuf可读字节的一部分。 修改返回的ByteBuf或当前ByteBuf会影响彼此的内容 同时它们维护单独的索引和标记,此方法不会修改当前ByteBuf的readerIndex或writerIndex *另请注意此方法不会调用{link #retain()}因此不会增加引用计数 slice() 等同于 slice(buffer.readerIndex(), buffer.readableBytes())默认截取 readerIndex 到 writerIndex 之间的数据最大容量 maxCapacity 为原始 ByteBuf 的可读取字节数底层分配的内存、引用计数都与原始的 ByteBuf 共享。 duplicate() duplicate() 与 slice() 不同的是duplicate()截取的是整个原始 ByteBuf 信息底层分配的内存、引用计数也是共享的。如果向 duplicate() 分配出来的 ByteBuf 写入数据那么都会影响到原始的 ByteBuf 底层数据。 返回共享当前ByteBuf信息的新ByteBuf,他们使用独立的readIndex writeIndex markIndex *修改返回的ByteBuf或当前ByteBuf会影响彼此的内容同时它们维护单独的索引和标记, *此方法不会修改当前ByteBuf的readerIndex或writerIndex 另请注意此方法不会调用{link #retain()}因此不会增加引用计数 copy() 会从原始的 ByteBuf 中拷贝所有信息所有数据都是独立的向 copy() 分配的 ByteBuf 中写数据不会影响原始的 ByteBuf。 返回ByteBuf的可读字节的拷贝。修改返回的ByteBuf内容与当前ByteBuf完全不会相互影响。 此方法不会修改当前ByteBuf的readerIndex或writerIndex 到底为止ByteBuf 的核心 API 我们基本已经介绍完了ByteBuf 读写指针分离的小设计确实带来了很多实用和便利的功能在开发的过程中不必再去想着 flip、rewind 这种头疼的操作了。 内存管理 API 未池化堆内存 java ByteBuf heapByteBuf Unpooled.buffer(10); 未池化直接内存 java ByteBuf directByteBuf Unpooled.directBuffer(10); 池化堆内存 java PooledByteBufAllocator allocator new PooledByteBufAllocator(false); ByteBuf pHeapByteBuf allocator.buffer(); 池化直接内存 java PooledByteBufAllocator allocator2 new PooledByteBufAllocator(true); ByteBuf 实战演练 学习完 ByteBuf 的内部构造以及核心 API 之后我们下面通过一个简单的示例演示一下 ByteBuf 应该如何使用代码如下所示。 java public class ByteBufTest { public static void main(String[] args) { // static final ByteBufAllocator DEFAULT_ALLOCATOR; // 根据allocType创建不同的分配器 如果没有值默认使用池化技术 // alloc UnpooledByteBufAllocator.DEFAULT; // alloc PooledByteBufAllocator.DEFAULT; // 初始是6 最大是10 ByteBuf buffer ByteBufAllocator.DEFAULT.buffer(6, 10); printByteBufInfo(ByteBufAllocator.buffer(5, 10), buffer); buffer.writeBytes(new byte[]{1, 2}); printByteBufInfo(write 2 Bytes, buffer); buffer.writeInt(100); printByteBufInfo(write Int 100, buffer); buffer.writeBytes(new byte[]{3, 4, 5}); printByteBufInfo(write 3 Bytes, buffer); byte[] read new byte[buffer.readableBytes()]; buffer.readBytes(read); printByteBufInfo(readBytes( buffer.readableBytes() ), buffer); printByteBufInfo(BeforeGetAndSet, buffer); System.out.println(getInt(2): buffer.getInt(2)); buffer.setByte(1, 0); System.out.println(getByte(1): buffer.getByte(1)); printByteBufInfo(AfterGetAndSet, buffer); } private static void printByteBufInfo(String step, ByteBuf buffer) { System.out.println(------ step -----); System.out.println(readerIndex(): buffer.readerIndex()); System.out.println(writerIndex(): buffer.writerIndex()); System.out.println(isReadable(): buffer.isReadable()); System.out.println(isWritable(): buffer.isWritable()); System.out.println(readableBytes(): buffer.readableBytes()); System.out.println(writableBytes(): buffer.writableBytes()); System.out.println(maxWritableBytes(): buffer.maxWritableBytes()); System.out.println(capacity(): buffer.capacity()); System.out.println(maxCapacity(): buffer.maxCapacity()); } } java ------ByteBufAllocator.buffer(5, 10)----- readerIndex(): 0 writerIndex(): 0 isReadable(): false isWritable(): true readableBytes(): 0 writableBytes(): 6 maxWritableBytes(): 10 capacity(): 6 maxCapacity(): 10 ------write 2 Bytes----- readerIndex(): 0 writerIndex(): 2 isReadable(): true isWritable(): true readableBytes(): 2 writableBytes(): 4 maxWritableBytes(): 8 capacity(): 6 maxCapacity(): 10 ------write Int 100----- readerIndex(): 0 writerIndex(): 6 isReadable(): true isWritable(): false readableBytes(): 6 writableBytes(): 0 maxWritableBytes(): 4 capacity(): 6 maxCapacity(): 10 ------write 3 Bytes----- readerIndex(): 0 writerIndex(): 9 isReadable(): true isWritable(): true readableBytes(): 9 writableBytes(): 1 maxWritableBytes(): 1 capacity(): 10 maxCapacity(): 10 ------readBytes(0)----- readerIndex(): 9 writerIndex(): 9 isReadable(): false isWritable(): true readableBytes(): 0 writableBytes(): 1 maxWritableBytes(): 1 capacity(): 10 maxCapacity(): 10 ------BeforeGetAndSet----- readerIndex(): 9 writerIndex(): 9 isReadable(): false isWritable(): true readableBytes(): 0 writableBytes(): 1 maxWritableBytes(): 1 capacity(): 10 maxCapacity(): 10 getInt(2): 100 getByte(1): 0 ------AfterGetAndSet----- readerIndex(): 9 writerIndex(): 9 isReadable(): false isWritable(): true readableBytes(): 0 writableBytes(): 1 maxWritableBytes(): 1 capacity(): 10 maxCapacity(): 10 结合代码示例我们总结一下 ByteBuf API 使用时的注意点 write 系列方法会改变 writerIndex 位置当 writerIndex 等于 capacity 的时候Buffer 置为不可写状态向不可写 Buffer 写入数据时Buffer 会尝试扩容但是扩容后 capacity 最大不能超过 maxCapacity如果写入的数据超过 maxCapacity程序会直接抛出异常read 系列方法会改变 readerIndex 位置get/set 系列方法不会改变 readerIndex/writerIndex 位置。 总结 Netty 强大的数据容器 ByteBuf它不仅解决了 JDK NIO 中 ByteBuffer 的缺陷而且提供了易用性更强的接口。很多开发者已经使用 ByteBuf 代替 ByteBuffer即便他没有在写一个网络应用也会单独使用 ByteBuf。ByteBuf 作为 Netty 中最基础的数据结构。
http://www.dnsts.com.cn/news/98853.html

相关文章:

  • 做网站我网站找第三方支付如何修改wordpress的域名
  • wordpress站点更换域名广告设计找工作
  • 合肥外贸网站建设公司价格有域名了怎么建站
  • 单页面网站教程网站和discuz同步登录
  • 什么是网站黏着度商标注册45大类明细
  • 拖拽建站系统源码建外贸企业网站
  • 建设外贸型网站流程平顶山工程造价信息网
  • 做天猫还是做网站推广详情页面设计
  • 哪个网站做漫画可以有钱北京朝林建设集团网站
  • wordpress建站要钱么网上怎样找装修设计师
  • 矿泉水网站模板互联网营销师证书
  • 登陆工伤保险网站 提示未授权 怎么做网站制作的管理
  • 什么网站做视频赚钱南宁推广平台
  • 2万块建一个网站贵吗完整网页开发
  • 专门做教育咨询有限公司网站重庆网站制作建设
  • 公司网站要备案吗上海专建贸易有限公司
  • 免费网站浏览器网站建设的一般流程
  • 建设项目自主验收网站seo优化推广流程
  • 网站标题改了开发区建设业联合会网站
  • 南阳网站推广排名我想做个网站找谁做
  • 黑龙江建设网站招聘python 做网站速度
  • 成品影视app开发月光宝盒怎么样漳州seo网站快速排名
  • 广州市网站设计公司常用网站字体
  • 兰州网站建设营销q479185700刷屏上海做宴会的网站
  • 官方制作网站拼多多开网店怎么开 新手
  • 网页建立网站平台手机 网站 源码
  • 英文杭州网站建设软件技术专业可以从事什么工作
  • 网站 制作软件太原住房与城乡建设厅网站
  • 海口cms模板建站没有做网站能备案吗
  • 很多搜索词网站怎样做虚拟机做局域网网站服务器配置