Netty源码(一):Netty中的Buffer
来源:互联网 发布:淘宝发货打印软件 编辑:程序博客网 时间:2024/05/22 00:53
最近我学习了NIO相关的知识,然后发现了Netty这个基于NIO的网络应用框架,于是就研究起Netty框架源码,来好好体会一下网络框架的设计理念和思想.
这个系列的文章不仅会总结Netty各个模块的源码原理,也会写出一些自己对这些设计的理解和体会.
我基本按照并发编程网上这个系列文章的顺序来进行系列文章的顺序,不同的是我是基于Netty4.1的源码进行分析和讲解.
为了节约你的时间,本篇文章主要内容如下:
- Netty的Buffer的内存模型,涉及读写指针
- Netty的Buffer框架
- Netty的Pool原理,轻量对象池
Buffer
Java NIO中的Buffer用于和NIO通道进行交互,数据可以从通道读入缓冲区,也可以从缓冲区写入到通道中.所以说,Buffer其实就是一块可以读写数据的内存,我们将其包装为一个Java对象来提供一系列读写操作.
Netty并没有直接使用Java NIO的Buffer实现,而是自己实现了一套Buffer框架来满足自己的业务或者性能需求.
ByteBuf的基本原理
读写指针的作用
不同于NIO Buffer的读写指针共用原理,ByteBuf拥有readerIndex
,writerIndex
两个指针.下面我们就来详细的讲解一下ByteBuf的内部原理.
+-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | | | (CONTENT) | | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex <= writerIndex <= capacity
从示意图中我们可以看出readerIndex
和writerIndex
最多可以将整个内容空间划分为三块:废弃区
,可读区
和可写区
.下面我们就来看一下不同操作下的两个指针的变化.
- 在初始化状态下,假设capacity为20,readerIndex
和writerIndex
都为0,整个空间中只存在可写区.此时只能写,不能读,进行读操作会抛出异常.
+---------------------------------------------------------+ | writable bytes (got more space) | +---------------------------------------------------------+ | | readerIndex(0) writerIndex(0) <= capacity
- 写入10个字节的数据,
writerIndex
指向10,readerIndex
不会改变,所有内容空间中有可读区和可写区.大小都是10字节.
+-------------------+------------------+------------------+ | readable bytes | writable bytes | | (CONTENT) | | +--------- --------+------------------+------------------ | | | readerIndex(0) <= writerIndex(10) <= capacity
- 读取5个字节的内容,
writerIndex
不变,readerIndex
加5,指向了5.此时内容空间分为了5字节的废弃区,5字节的可读区和10字节的可写区.
+-------------------+------------------+------------------+ | discardable bytes | readable bytes | writable bytes | | | (CONTENT) | | +-------------------+------------------+------------------+ | | | | 0 <= readerIndex(5) <= writerIndex(10) <= capacity
- 调用
discardReadBytes
方法后,将废弃区的内容舍弃掉,readerIndex
又指向了0,writerIndex
指向了5,相当于可读区和可写区整体向左平移了5个字节.
+------------------+--------------------------------------+ | readable bytes | writable bytes (got more space) | +------------------+--------------------------------------+ | | | readerIndex (0) <= writerIndex (5) <= capacity
零拷贝
OS层次上Zero-copy
,就是在操作数据时,不需要将数据buffer从一个内存区域拷贝到另一个内存区域,因为减少了一次内存的拷贝,因此CPU的效率得到了提升.
Netty
的zero-copy
体现在很多方面.比如Buffer的compose,duplicate,slice操作时不会拷贝底层的数据.而是通过ByteBuf对象的组合来实现上述的操作
- Netty提供了CompositeByteBuf
类,可以将多个ByteBuf
组合成一个逻辑上的Buffer,避免了各个buffer之间的拷贝,CompositeByteBuf
并不拥有底层的数据,而是通过拥有两个buffer对象,从这两个buffer对象中获取数据来对外提供看似合并了的数据.比如我们将一份协议数据的头部buffer和消息体buffer合并成一个Buffer.
如上图所示,所有底层的数据还是存储在header和body这两个真实的buffer中.
- 对于
ByteBuf
的slice
和duplicate
操作也是如此,不同的buffer共享了相同的底层数据,而不是进行底层数据的拷贝.具体使用到的Buffer类型为DuplicatedByteBuf
和SlicedByteBuf
.谁说是共享的底层数据,但是通过对writerIndex
和readerIndex
两个指针的操作来实现slice和duplicate的功能. - Netty使用
wrap
操作将byte数组转化为ByteBuf
对象时,将byte数组包裹到对象中,而不是拷贝数组存放到对象中. - Netty 中使用 FileRegion 实现文件传输的零拷贝, 不过在底层 FileRegion 是依赖于 Java NIO FileChannel.transfer 的零拷贝功能.
Pool和Reference Count
4.0之后的版本实现了高性能的Buffer池,分配策略则是结合了buddy allocation和slab allocation的jemalloc变种,实现类为PoolArena
,这样的话,可以在频繁分配和释放Buffer时缓解GC压力,还可以在初始化新buffer时减少内存带宽消耗(初始化时不可避免的要给buffer数组赋初始值).
ByteBuf
引入了Reference Count
机制,你需要在不适用它的时候调用ReferenceCountUtil.release
方法来减少它的引用.
后记
感觉自己在研究或在阅读源代码时还是有些问题,起始ByteBuf
并不是Netty
的关键所在,不应该花费这么长时间.以后还是要带着目的来看源码,不能把时间浪费在一些代码细节上.
引用
- https://segmentfault.com/a/1190000007560884
- Netty源码(一):Netty中的Buffer
- Netty源码解读 Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- Netty源码解读(二)Netty中的buffer
- netty 源码分析一
- netty源码分析一
- Netty那点事(二)Netty中的buffer
- Netty那点事(二)Netty中的buffer
- Netty那点事(2)Netty中的buffer
- 【转】Netty那点事(二)Netty中的buffer
- 【转】Netty那点事(二)Netty中的buffer
- netty源码分析(一)-启动
- Netty源码学习(一)----概述
- 求最大字段和
- Linux安装配置Mysql及优化(一)
- Node.js连接mysql数据库
- [算法练习]选择排序的C语言实现
- AFN框架(二)的使用和有关序列化器的问题--缓存机制------
- Netty源码(一):Netty中的Buffer
- [PAT][GPLT][CCCC]L1-020.帅到没朋友
- 级数求和 C# lanmda写法
- Bootstrap 图标
- (反射方法)写一个将一个String类型的json经过base64加密后解密转化成javaBean的工具类
- Hadoop 从 hdfs 中拷出文件权限不够
- [参考]Hadoop集群完全分布式模式环境部署
- Oracle数据库的查询之基本查询(一)
- Android将Excel表数据导入SQLite数据库