1. Netty中的缓冲

在Netty中并没有使用Java自带的ByteBuffer,而是自己实现提供了一个缓存区来用于标识一个字节序列,并帮助用户操作原始字节或者自定义的POJO。

Java NIO的ByteBuffer问题

  • 长度固定,不能动态扩展和收缩
  • 只有一个标识位置的指针,读写时要手动调用相关方法
  • API功能有限,需要自己实现更高级的功能

如上图,channel与对端的I/O读写都要操作Buffers。当有读操作时,把数据从内核区读取到用户区,当有写操作时,把数据从用户区写到内核区。

2. ByteBuf

ByteBuf是Netty的实现的最基本的数据缓冲,它包括Heap Buffer和Direct Buffer。

ByteBuf实现了高级的功能和API,是Java NIO ByteBuffer更高级的封装和实现。

2.1 ByteBuf结构

如上图是ByteBuf的结构,其中:

  • readerIndex:读指针,最开始时等于0
  • writerIndex:写指针,最开始时等于0
  • capacity:代表这块内存区域的大小

2.2 写入数据

当写入N个数据后,writerIndex向后移动,但要保证writerIndex<capacity,这时可读数据为writerIndex,可写数据长度为capacity-writerIndex

2.3 读取数据

每读一个数据,readerIndex向后移动,但readerIndex<=writerIndex,可读数据writerIndex-readerIndex这时readerIndex-0则是可丢弃的数据段

2.4 动态扩展

如果数据继续写入缓冲区,而缓存区的writable区间已经被判断空间不足,那就有两个方法可以解决:
  • 动态扩展缓冲区,由ByteBuf实现

    重新创建一个新的ByteBuffer,并将之前的ByteBuffer复制到新创建的ByteBuffer中,最后释放老的ByteBuffer

  • 重用discard 区域,需要调用discardReadBytes方法

2.5 Heap Buffer

Heap Buffer:堆内存字节缓存区,特点是内存的分配和回收速度快,但在I/O读写时需要额外一次内存复制,将堆内存对应的缓冲区复制到内核Channel中。

2.6 Direct Buffer

Direct Buffer:直接内存字节缓存区,直接从Socket Channel中读写数据,少了一次内存复制,但内存的分配和回收速度慢一些。

2.7 Composite Buffer

Composite Buffer:复合缓冲区,我们可以创建多个不同的ByteBuf,然后提供一个这些ByteBuf 组合的视图。复合缓冲区就像一个列表,我们可以动态的添加和删除其中的ByteBuf

2.8 引用计数

ByteBuf扩展了ReferenceCountered接口,这个接口定义的功能主要是引用计数。
通过refCnt的数值来计算ByteBuf,如果refCnt等于1了,调用deallocate来回收ByteBuf,对于池化的ByteBuf则放入内存池,其他则释放内存。

3. 缓冲对象池

Netty使用Recycler来实现轻量级缓冲对象池。

3.1 Recycler

  • Handle

    定义接口

  • Stack

    Stack具体维护着对象池数据,向Recycler提供push和pop两个主要访问接口,pop用于从内部弹出一个可被重复使用的对象,push用于回收以后可以重复使用的对象

  • elements

    对象池数组

3.1.1 get

  • 首先获得当前线程关联的stack
  • 从stack中pop出一个handle
  • 如果没有则k新建一个
  • 从handle中取出对象

3.1.2 recycle

  • 对象通过引用计数来管理,如果发现引用计数等于1了,就通知Recycler回收对象
  • 将对象放入stack中
  • 如果超过当前池的大小但还没达到最大值,则新建池,并拷贝对象

3.2 内存池总结

Netty中每个线程都关联着一个内存对象池,用来操作缓冲对象

Netty中的I/O操作都需要涉及缓冲区,如果不使用内存池技术,系统将频繁的创建和回收buffer,对buffer的管理将十分困难。对于HeapBuf和Directbuf都分配和释放频率,并且对于Directbuf弥补一定的分配回收代价。

4. Zero-Copy

  • Netty 提供了 CompositeByteBuf 类, 它可以将多个 ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了各个 ByteBuf 之间的拷贝

  • 通过 wrap 操作, 我们可以将 byte[] 数组、ByteBuf、ByteBuffer等包装成一个 Netty ByteBuf 对象, 进而避免了拷贝操作

  • ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf, 避免了内存的拷贝

  • 通过 channel的tranferTo 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题.

Netty学习五:Buffers的更多相关文章

  1. Netty学习(五)-DelimiterBasedFrameDecoder

    上一节我们说了LineBasedframeDecoder来解决粘包拆包的问题,TCP以流的方式进行数据传输,上层应用协议为了对消息进行区分,一般采用如下4种方式: 消息长度固定,累计读取到消息长度总和 ...

  2. Netty 学习(五):服务端启动核心流程源码说明

    Netty 学习(五):服务端启动核心流程源码说明 作者: Grey 原文地址: 博客园:Netty 学习(五):服务端启动核心流程源码说明 CSDN:Netty 学习(五):服务端启动核心流程源码说 ...

  3. Netty 学习笔记(1)通信原理

    前言 本文主要从 select 和 epoll 系统调用入手,来打开 Netty 的大门,从认识 Netty 的基础原理 —— I/O 多路复用模型开始.   Netty 的通信原理 Netty 底层 ...

  4. Netty学习笔记-入门版

    目录 Netty学习笔记 前言 什么是Netty IO基础 概念说明 IO简单介绍 用户空间与内核空间 进程(Process) 线程(thread) 程序和进程 进程切换 进程阻塞 文件描述符 文件句 ...

  5. netty学习资料

    netty学习资料推荐官方文档和<netty权威指南>和<netty in action>这两本书.下面收集下网上分享的资料 netty官方参考文档 Netty 4.x Use ...

  6. Netty学习之客户端创建

    一.客户端开发时序图 图片来源:Netty权威指南(第2版) 二.Netty客户端开发步骤 使用Netty进行客户端开发主要有以下几个步骤: 1.用户线程创建Bootstrap Bootstrap b ...

  7. TweenMax动画库学习(五)

    目录            TweenMax动画库学习(一)            TweenMax动画库学习(二)            TweenMax动画库学习(三)            Tw ...

  8. netty学习资源收集

    Netty学习笔记 Netty In Actions CSDN专栏 一起学Netty-CSDN专栏 Netty In Action中文版

  9. Netty 学习 一、初识Netty【原创】

    在过去几年的工作和学习中,比较关注高层次的应用开发,对底层探究较少.实现Web应用的开发,主要依赖Tomcat.Apache等应用服务器,程序员无需了解底层协议,但同样限制了应用的性能和效率.现在开始 ...

随机推荐

  1. 访问控制public/protected/private的区别

    Java支持四种不同的访问权限: 修饰符 说明 public 共有的,对所有类可见. protected 受保护的,对同一包内的类和所有子类可见. private 私有的,在同一类内可见. 默认的 在 ...

  2. 用js写的比较简单3D旋转效果

    HTML代码如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  3. EDA技术与ASIC设计和FPGA开发有什么关系?FPGA在ASIC设计中有什么用途?

    利用EDA技术进行电子系统设计的最后目标是完成专用集成电路ASIC的设计和实现:FPGA和CPLD是实现这一途径的主流器件.FPGA和CPLD通常也被称为可编程专用IC,或可编程ASIC.FPGA和C ...

  4. Linux初记

    ctrl+u可以在shell下删除行,如果此键不起作用,就试试ctrl+x ctrl+z可以将程序挂起,不会终止程序,但可以将程序挂起. 通过fg命令可再把此作业切换到前台 cp命令的目标文件如果是一 ...

  5. 视频文件写入转换之图像处理-OpenCV应用学习笔记五

    在<笔记二>中我们做了视频播放和控制的实现,仅仅算是完成了对视频文件的读取操作:今天我们来一起练习下对视频文件的写入操作:格式转换. 实现功能: 打开一个视频文件play.avi,读取文件 ...

  6. 【C-分支结构】

    一.关系运算符 双目运算符 自左向右结合 关系运算符的优先级低于算术运算符,高于赋值运算符 <(小于) <=(小于或等于) >(大于) >=(大于或等于) ==(等于) !=( ...

  7. slot游戏中的数学概念

    最近研究slot 算法,看了大量的英文资料,因为母语中文,一直使用中文的英文小白来说,好心塞,悔不当初没学好英文. 下文是从众多的英文中摘录的唯一能够看明白的概念.先给自己留着,到时候深入研究可以看 ...

  8. java 并发性和多线程 -- 读感 (二 线程间通讯,共享内存的机制)

    参考文章:http://ifeve.com/java-concurrency-thread-directory/ 其中的竞态,线程安全,内存模型,线程间的通信,java ThreadLocal类小节部 ...

  9. dbstart和dbshut启动、关闭数据库报错ORACLE_HOME_LISTNER is not SET解决办法

    dbstart启动数据库报错,如下: [oracle@wen ~]$ dbstartORACLE_HOME_LISTNER is not SET, unable to auto-start Oracl ...

  10. Percona Server 5.6.13-61.0 首个 GA 版本发布

    Percona Server 5.6 的首个 GA 版本发布了,版本号是 5.6.13-61.0 ,该版本基于 MySQL 5.6.13 改进内容包括: New Features: Percona S ...