一起学Netty(五)之 初识ByteBuf和ByteBuf的常用API

网络传输的载体是byte,这是任何框架谁也逃脱不了的一种规定,JAVA的NIO提供了ByteBuffer,用来完成这项任务,当然ByteBuffer也很好的完成了这个任务,Netty也提供了一个名字很相似的载体叫做ByteBuf,相比于ByteBuf而言,它有着更加更多友善的API,也更加易于维护,并且它可以扩容

一般来说,ByteBuf都是维护一个byte数组的,它的内部格式是长成这个样子的

 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      |                   |     (CONTENT)    |                  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity

与原生态的ByteBuffer相比,它维护了两个指针,一个是读指针,一个是写指针,而原生态的ByteBuffer只维护了一个指针,你需要调用flip方法来切换读写的状态,不易用户管理维护

读的时候,可读的区域是下标区间是[readerIndex,writeIndex),可写区间的是[writerIndex,capacity-1],但是discardable这段区间就会变得相对无用,既不能读,也不能写

所以我们可以使用discardReadBytes的方法进行内存空间的回收,回收之后是这样的:

 *      +------------------+--------------------------------------+
 *      |  readable bytes  |    writable bytes (got more space)   |
 *      +------------------+--------------------------------------+
 *      |                  |                                      |
 * readerIndex (0) <= writerIndex (decreased)        <=        capacity

discardReadBytes之后,可读段被移到了该内存空间的最左端,可写段从空间容量来说,变大了,变成了回收之前的可写段+discard段内存之和,这样做的唯一问题就是性能问题,因为可读段的字节迁移问题,如果大量调用该方法,会产生很多的复制操作,所以除非能获取discard的很大空间,一般情况下,高并发的情况下,不适合多调用

当然还有clear方法,这个方法简单易懂,调用之前ByteBuf是长成这样的:

 *      +-------------------+------------------+------------------+
 *      | discardable bytes |  readable bytes  |  writable bytes  |
 *      +-------------------+------------------+------------------+
 *      |                   |                  |                  |
 *      0      <=      readerIndex   <=   writerIndex    <=    capacity

调用完之后是长成这样的:

 *      +---------------------------------------------------------+
 *      |             writable bytes (got more space)             |
 *      +---------------------------------------------------------+
 *      |                                                         |
 *      0 = readerIndex = writerIndex            <=            capacity

ByteBuf除了discardReadBytes和clear方法之外,还提供了大量的丰富的读写方法,此处就不一一列举了

还有几个比较重要的API,这里也说明一下

1)duplicate方法:复制当前对象,复制后的对象与前对象共享缓冲区,且维护自己的独立索引

2)copy方法:复制一份全新的对象,内容和缓冲区都不是共享的

3)slice方法:获取调用者的子缓冲区,且与原缓冲区共享缓冲区

关于ByteBuf一些比较重要的API的认识就是这些,因为我目前还没有使用的一些心得,希望以后有机会分享

我们再来看看ByteBuf的继承关系图:

强行盗了三张图,不管是从什么角度来分析,ByteBuf说到底还是维护了一个字节数组

目前为止,Netty提供来的ByteBuf都是堆内内存,大概是因为我们平时写的都是channel,写的是业务逻辑的代码

我们可以看到堆外内存分配的源代码:

    DirectByteBuffer(int cap) {                   // package-private

        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;

    }

并且在我们平时的普通开发中,用的也是Unpool类型的普通ByteBuf,但是在一些高并发的应用中,Pooled化的ByteBuf性能会更加优秀

关于ByteBuf初步的了解就这么多了,先暂时分享一下,希望以后能有其他的使用体会

时间: 2024-11-08 02:13:18

一起学Netty(五)之 初识ByteBuf和ByteBuf的常用API的相关文章

Mina、Netty、Twisted一起学(五):整合protobuf

protobuf是谷歌的Protocol Buffers的简称,用于结构化数据和字节码之间互相转换(序列化.反序列化),一般应用于网络传输,可支持多种编程语言. protobuf怎样使用这里不再介绍,本文主要介绍在MINA.Netty.Twisted中怎样使用protobuf,不了解protobuf的同学能够去參考我的还有一篇博文. 在前面的一篇博文中.有介绍到一种用一个固定为4字节的前缀Header来指定Body的字节数的一种消息切割方式.在这里相同要使用到. 仅仅是当中Body的内容不再是字

Netty in Action (十二) 第五章节 第一部分 简介ByteBuf

第五章 ByteBuf(分四部分翻译) 本章节包括: 1)ByteBuf------Netty的数据容器 2)API介绍 3)使用案例 4)内存分配 我们之前提到过很多次,网络传输数据的最基本的数据单元是byte,Java的NIO提供了ByteBuffer作为字节的容器,但是这个类的使用有些过于复杂和麻烦 Netty对ByteBuffer提供了一个可选方案ByteBuf,一个很好的解决方案,解决了JDK原生的ByteBuffer的API使用不易的问题,同时ByteBuf为应用程序开发者提供了一系

笨鸟学php(五) 函数的声明与使用

1.函数的声明 <?php /** * function 函数名(参数1, 参数2.... ){ * 函数体; * 返回值; * } */ $sum = sum(3, 4); echo $sum; function sum($x, $y){ $sum = 0; $sum = $x * $x + $y + $y; return $sum; } ?> 2.变量的范围 局部变量: 在函数中声明的变量就是局部变量, 只能在自己的函数内部使用. 全局变量: 在函数外声明的变量就是全局变量, 在变量声明以

Netty——高级内置解码器、编码器、ByteBuf

netty通讯需要对数据进行编码,解码,于是我们需要用到netty的编码器.解码器   netty 提供的解码器 DelimiterBasedFrameDecoder 解决TCP的粘包解码器 StringDecoder 消息转成String解码器 LineBasedFrameDecoder 自动完成标识符分隔解码器 FixedLengthFrameDecoder 固定长度解码器,二进制 Base64Decoder base64 解码器 netty 提供的编码器 Base64Encoder bas

linux就该这么学第五课

linux就该这么学第五课 vim编辑器 命令模式 复制:yy 剪切删除:dd u:撤销上一步的操作 p:将之前操作的步骤返回 n/N:搜索下一个字符串/搜索上一个字符串 输入模式 直接输入即可,跟记事本一样 末行模式 :w保存 :q退出 q!:强制退出 :命令 直接执行相应命令 :整数 跳转到该行 输入模式无法直接进入末行模式,反之一样,都需要通过命令模式进入输入模式或者末行模式 编辑脚本 固定格式: #! /bin/bash #注释 相应命令 接受用户参数 $0:shell脚本的名称 $#:

Netty快速入门(08)ByteBuf组件介绍

前面的内容对netty进行了介绍,写了一个入门例子.作为一个netty的使用者,我们关注更多的还是业务代码.也就是netty中这两种组件: ChannelHandler和ChannelPipeline---对应于NIO中的客户逻辑实现handleRead/handleWrite(interceptor pattern) ByteBuf---- 对应于NIO 中的ByteBuffer 我们的业务逻辑要放在handler里面,读写数据用的是ByteBuf.其余的Transport.ServerBoo

一个老师程序员说:这是学Java 必知必会的 20 种常用类库和 API

一个有经验的Java开发人员特征之一就是善于使用已有的轮子来造车.<Effective Java>的作者Joshua Bloch曾经说过:"建议使用现有的API来开发,而不是重复造轮子".在本文中,我将分享一些Java开发人员应该熟悉的最有用的和必要的库和API.顺便说一句,这里不包括框架,如Spring和Hibernate因为他们非常有名,都有特定的功能.最后,如果大家如果在自学遇到困难,想找一个java的学习环境,可以加入我们的java学习圈,点击我加入吧,会节约很多时

Activiti学习笔记五 — 常用API解析

常用API解析: 一.ProcessEngineConfiguration 流程引擎配置对象(配置数据库连接4个大配置和建表策略) 二.ProcessEngine          流程引擎核心对象(服务大管家) 三.RepositoryService     仓库服务.管理规则相关的信息. 四.RuntimeService     运行时服务. 负责流程的启动,查看,执行等操作. 五.TaskService          任务服务.管理任务的查看,接手,办理等操作. 六.规则管理相关: 1

三十五、 rsync工具介绍、rsync常用选项、rsync通过ssh同步

三十五. rsync工具介绍.rsync常用选项.rsync通过ssh同步 一.rsync工具 数据备份,很重要. rsync工具:数据备份的工具.remote sync(远程同步) rsync可以远程同步数据(类似scp),也可以本地同步数据(类似cp). 不同于cp或scp的是,它不会覆盖以前的数据(当数据已存在),而是先判断已存在的数据和新数据的差异,只有数据不同时才会把不同的部分覆盖. 若没有rsync命令,就yum install -y rsync安装. # rsync -av /et