Netty Review - ByteBuf内存池源码解析

文章目录

  • Pre
  • 主要特点和工作原理
  • 类关系
  • 源码解析
    • 入口索引
    • AbstractNioByteChannel.NioByteUnsafe#read
    • allocHandle.allocate(allocator)
  • 小结

在这里插入图片描述

在这里插入图片描述


Pre

Netty Review - 直接内存的应用及源码分析

Netty Review - 底层零拷贝源码解析


主要特点和工作原理

ByteBuf 内存池是 Netty 中用于管理 ByteBuf 对象的一种机制,旨在提高内存的使用效率和性能。

以下是 ByteBuf 内存池的主要特点和工作原理:

  1. 复用缓冲区对象:内存池会维护一组预分配的 ByteBuf 对象,这些对象可以被重复使用,避免了频繁地创建和销毁对象,从而减少了内存分配和释放的开销。

  2. 提高内存分配速度:由于预先分配了一定数量的 ByteBuf 对象,当需要分配新的缓冲区时,可以直接从内存池中获取可用的对象,避免了频繁地向操作系统请求内存,提高了分配速度。

  3. 减少内存碎片:内存池会根据需求预分配一定数量和大小的缓冲区对象,这些对象大小一致或相近,有利于减少内存碎片的产生。

  4. 提高性能:通过复用缓冲区对象和减少内存分配和释放的次数,可以降低系统的开销,提高了系统的性能。

  5. 线程安全:内存池通常是线程安全的,多个线程可以并发地从内存池中获取和释放缓冲区对象,而不需要额外的同步措施。

工作原理:

  • 当需要分配缓冲区对象时,首先尝试从内存池中获取可用的对象。
  • 如果内存池中没有可用的对象,则根据需求创建新的缓冲区对象。
  • 当缓冲区对象不再使用时,将其归还给内存池,以便重复利用。

类关系

在这里插入图片描述

在这里插入图片描述


源码解析

入口索引

结合我们的Netty线程模型源码图 ,找到入口 。

在这里插入图片描述

AbstractNioByteChannel.NioByteUnsafe#read

这段代码是 Netty 中的 read() 方法实现,用于从通道中读取数据并触发相应的事件到 ChannelPipeline 中。

@Override
public final void read() {final ChannelConfig config = config();  // 获取通道配置信息if (shouldBreakReadReady(config)) {  // 判断是否应该中断读就绪操作clearReadPending();  // 清除读等待标志return;}final ChannelPipeline pipeline = pipeline();  // 获取通道的管道final ByteBufAllocator allocator = config.getAllocator();  // 获取分配器final RecvByteBufAllocator.Handle allocHandle = recvBufAllocHandle();  // 获取接收字节缓冲区分配句柄allocHandle.reset(config);  // 重置分配句柄状态ByteBuf byteBuf = null;  // 字节缓冲区boolean close = false;  // 是否关闭标志try {do {byteBuf = allocHandle.allocate(allocator);  // 分配字节缓冲区allocHandle.lastBytesRead(doReadBytes(byteBuf));  // 读取数据到缓冲区if (allocHandle.lastBytesRead() <= 0) {// 如果没有读取到数据// 释放缓冲区byteBuf.release();byteBuf = null;close = allocHandle.lastBytesRead() < 0;  // 是否关闭标志if (close) {// 如果收到 EOF,表示没有数据可读了readPending = false;  // 清除读等待标志}break;}allocHandle.incMessagesRead(1);  // 增加读取消息数readPending = false;  // 清除读等待标志pipeline.fireChannelRead(byteBuf);  // 触发通道读事件到管道byteBuf = null;} while (allocHandle.continueReading());  // 继续读取数据,直到不再需要读取为止allocHandle.readComplete();  // 读操作完成pipeline.fireChannelReadComplete();  // 触发通道读完成事件到管道if (close) {closeOnRead(pipeline);  // 如果需要关闭通道,执行关闭操作}} catch (Throwable t) {handleReadException(pipeline, byteBuf, t, close, allocHandle);  // 处理读取异常} finally {// 检查是否有未处理的读等待操作// 这可能有两个原因:// 1. 用户在 channelRead(...) 方法中调用了 Channel.read() 或 ChannelHandlerContext.read()// 2. 用户在 channelReadComplete(...) 方法中调用了 Channel.read() 或 ChannelHandlerContext.read()// 详见 https://github.com/netty/netty/issues/2254if (!readPending && !config.isAutoRead()) {removeReadOp();  // 移除读操作}}
}

allocHandle.allocate(allocator)

在这里插入图片描述

@Override
public ByteBuf allocate(ByteBufAllocator alloc) {return alloc.ioBuffer(guess());
}

在给定的 ByteBufAllocator 上分配一个新的 ByteBuf 实例。

  • return alloc.ioBuffer(guess()): 使用给定的 ByteBufAllocator 对象调用 ioBuffer() 方法来分配一个新的 ByteBuf 实例。guess() 方法用于估算分配的字节数。

该方法的作用是在给定的 ByteBufAllocator 上分配一个新的 ByteBuf 实例,并返回分配的实例。


在这里插入图片描述

alloc.ioBuffer(guess())

@Override
public ByteBuf ioBuffer(int initialCapacity) {if (PlatformDependent.hasUnsafe()) { // 检查当前平台是否支持直接内存return directBuffer(initialCapacity); // 如果支持直接内存,则调用 directBuffer() 方法创建直接内存的 ByteBuf 实例}return heapBuffer(initialCapacity); // 如果不支持直接内存,则调用 heapBuffer() 方法创建堆内存的 ByteBuf 实例
}

该方法的作用是根据当前平台是否支持直接内存来选择合适的内存类型(堆内存或直接内存),并根据传入的初始容量参数创建相应类型的 ByteBuf 实例

PlatformDependent.hasUnsafe() ---- true

   @Override
public ByteBuf directBuffer(int initialCapacity) {return directBuffer(initialCapacity, DEFAULT_MAX_CAPACITY); // 调用重载方法 directBuffer(int initialCapacity, int maxCapacity),传入默认的最大容量值 DEFAULT_MAX_CAPACITY
}

directBuffer(initialCapacity, DEFAULT_MAX_CAPACITY);

@Override
public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {if (initialCapacity == 0 && maxCapacity == 0) { // 如果初始容量和最大容量都为0return emptyBuf; // 返回一个空的 ByteBuf 实例}validate(initialCapacity, maxCapacity); // 验证初始容量和最大容量的合法性return newDirectBuffer(initialCapacity, maxCapacity); // 创建一个新的直接内存的 ByteBuf 实例
}

newDirectBuffer方法,我们发现它是一个抽象方法,由AbstractByteBufAllocator的子类负责具体实现

在这里插入图片描述

newDirectBuffer(initialCapacity, maxCapacity)

@Override
protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {// 获取当前线程的线程缓存PoolThreadCache cache = threadCache.get();// 获取直接内存池PoolArena<ByteBuffer> directArena = cache.directArena;final ByteBuf buf;if (directArena != null) { // 如果直接内存池可用// 从直接内存池中分配内存buf = directArena.allocate(cache, initialCapacity, maxCapacity);} else { // 如果直接内存池不可用// 使用平台相关的方式创建直接内存的 ByteBuf 实例buf = PlatformDependent.hasUnsafe() ?UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);}// 返回一个包装了泄漏感知器的 ByteBuf 实例return toLeakAwareBuffer(buf);
}

directArena.allocate(cache, initialCapacity, maxCapacity);

PooledByteBuf<T> allocate(PoolThreadCache cache, int reqCapacity, int maxCapacity) {// 创建一个新的 PooledByteBuf 实例,其中 maxCapacity 为指定的最大容量PooledByteBuf<T> buf = newByteBuf(maxCapacity);// 使用指定的线程缓存和请求容量来分配内存给 ByteBufallocate(cache, buf, reqCapacity);// 返回分配的 ByteBufreturn buf;
}

这段代码实现了从线程缓存中分配内存给 ByteBuf,并返回分配的 ByteBuf 实例。

重点分析newByteBuf的实现,它同样是个抽象方法,由子类DirectArena和HeapArena来实现不同类型的缓冲区分配.

在这里插入图片描述

我们这里使用的是直接内存,因此重点分析DirectArena的实现

@Override
protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) {// 如果支持 Unsafeif (HAS_UNSAFE) {// 创建 PooledUnsafeDirectByteBuf 的实例return PooledUnsafeDirectByteBuf.newInstance(maxCapacity);} else {// 创建 PooledDirectByteBuf 的实例return PooledDirectByteBuf.newInstance(maxCapacity);}
}

这段代码是 Netty 中用于创建新的 PooledByteBuf 对象的方法。根据是否支持 Unsafe,选择创建 PooledUnsafeDirectByteBuf 或者 PooledDirectByteBuf 的实例。这两个类都是用于管理直接内存的缓冲区,其中 PooledUnsafeDirectByteBuf 是使用 Unsafe 的方式来操作内存,而 PooledDirectByteBuf 则是不依赖 Unsafe 来操作内存。


PooledUnsafeDirectByteBuf.newInstance(maxCapacity)

static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {// 从对象池中获取 PooledUnsafeDirectByteBuf 实例PooledUnsafeDirectByteBuf buf = RECYCLER.get();// 重用实例并设置最大容量buf.reuse(maxCapacity);return buf;
}

通过RECYCLER的get方法循环使用ByteBuf对象,如果是非内存池实现,则直接创建一个新的ByteBuf对象.


小结

总的来说,ByteBuf 内存池通过复用缓冲区对象和减少内存分配和释放的开销,提高了内存的使用效率和性能,是 Netty 中重要的优化手段之一。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/258288.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【王道数据结构】【chapter5树与二叉树】【P159t17~19】【统考真题】

目录 2014年统考 2017年统考 2022年统考 2014年统考 #include <iostream> #include <stack> #include <queue> typedef struct treenode{int weight;struct treenode *left;struct treenode *right; }treenode,*ptreenode;ptreenode buytreenode(int x) {p…

【web | CTF】BUUCTF [BJDCTF2020]Easy MD5

天命&#xff1a;好像也挺实用的题目&#xff0c;也是比较经典吧 天命&#xff1a;把php的MD5漏洞都玩了一遍 第一关&#xff1a;MD5绕过 先声明一下&#xff1a;这题的MD5是php&#xff0c;不是mysql的MD5&#xff0c;把我搞迷糊了 一进来题目啥也没有&#xff0c;那么就要看…

解密输入输出迷局:蓝桥杯与ACM中C++/C语言常见问题揭秘

关于C中的常见输入输出汇总 带空格的字符串&#xff1a; ​ 对于这种输入方式我们选择使用gets() 函数来进行输入&#xff0c;gets用于从标准输入&#xff08;通常是键盘&#xff09;读取一行文本并将其存储为字符串&#xff0c;直到遇到换行符&#xff08;‘\n’&#xff09…

飞天使-k8s知识点20-kubernetes实操5-pod更新与暂停-statefulset

文章目录 资源调度 Deployment&#xff1a;扩缩容资源调度 Deployment&#xff1a;更新的暂停与恢复资源调度 StatefulSet&#xff1a;定义一个有状态服务headless service 金丝雀发布 资源调度 Deployment&#xff1a;扩缩容 扩容和缩容&#xff0c;常用的功能 scale[rootkub…

上位机图像处理和嵌入式模块部署(图像项目处理过程)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于一般的图像项目来说&#xff0c;图像处理只是工作当中的一部分。在整个项目处理的过程中有很多的内容需要处理&#xff0c;比如说了解需求、评…

二、ActiveMQ安装

ActiveMQ安装 一、相关环境二、安装Java8三、下载安装包四、启动五、其他命令六、开放端口七、后台管理 一、相关环境 环境&#xff1a;Centos7.9安装ActiveMQ版本&#xff1a;5.15.9JDK8 二、安装Java8 安装教程&#xff1a;https://qingsi.blog.csdn.net/article/details/…

react【三】受控组件/高阶组件/portals/fragment/严格模式/动画

文章目录 1、受控组件1.1 认识受控组件1.2 checkout1.3 selected1.4 非受控组件 2、高阶组件2.1 认识高阶组件2.2 应用1-props增强的基本使用2.3 对象增强的应用场景-context共享2.4 应用2-鉴权2.5 应用3 – 生命周期劫持2.6、高阶组件的意义 3、Portals4、fragment5、StrictMo…

17.3.1.6 自定义处理

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 模拟某款图像处理软件的处理&#xff0c;它只留下红色、绿色或者蓝色这样的单一颜色。 首先按照颜色划分了6个色系&#xff0c;分别…

disql备份还原

disql备份还原 前言 本文档根据官方文档&#xff0c;进行整理。 一、概述 在 disql 工具中使用 BACKUP 语句你可以备份整个数据库。通常情况下&#xff0c;在数据库实例配置归档后输入以下语句即可备份数据库&#xff1a; BACKUP DATABASE BACKUPSET db_bak_01;语句执行完…

java生态环境评价Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java 生态环境评价管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysq…

.netcore音乐播放器 musicPlayer

html音乐播放器 .net core mvc 音乐播放器 支持上传本地音乐到云端 支持通过文件夹创建歌单(不需要数据库和其他数据存储) 通过歌单分类 播放歌曲 支持播放暂停 上一首 下一首切换 支持显示歌曲列表 歌单切换 展示歌曲根据歌单名去获取歌曲显示 功能 版权原因 或者想创建自己的…

macOS 安装 conda

macOS 安装 conda 安装 conda参考 Conda是一个开源的软件包管理系统和环境管理系统&#xff0c;用于安装和管理软件包和其依赖项。 安装 conda mkdir miniconda3 cd miniconda3 bash Miniconda3-latest-MacOSX-x86_64.sh$ conda list参考 macOS 安装 conda开始使用conda

python+django学习交流论坛系统244t6

系统可以提供信息显示和相应服务&#xff0c;其管理员管理用户发布的博客文章以及用户之间的论坛交流信息&#xff0c;管理留言以及文章分类信息。用户在论坛交流模块发布帖子以及评论帖子&#xff0c;在前台查看和评论其他用户发布的博客文章&#xff0c;收藏博客文章&#xf…

esp8266-01s WIFI模块使用(一)- AT指令

时间记录&#xff1a;2024/2/15 一、注意事项 &#xff08;1&#xff09;使用英文双引号表示字符串数据 &#xff08;2&#xff09;默认波特率115200 &#xff08;3&#xff09;AT指令以“\r\n”结尾 &#xff08;4&#xff09;3.3V电源接口先连接单片机的3.3V&#xff0c;如…

阿里云“BGP(多线)”和“BGP(多线)_精品”区别价格对比

阿里云香港等地域服务器的网络线路类型可以选择BGP&#xff08;多线&#xff09;和 BGP&#xff08;多线&#xff09;精品&#xff0c;普通的BGP多线和精品有什么区别&#xff1f;BGP&#xff08;多线&#xff09;适用于香港本地、香港和海外之间的互联网访问。使用BGP&#xf…

用HTML5 Canvas创造视觉盛宴——动态彩色线条效果

目录 一、程序代码 二、代码原理 三、运行效果 一、程序代码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <!-- 声明文档类型为XHTML 1.0 Transitional -…

ElasticSearch之search API

写在前面 本文看下查询相关内容&#xff0c;这也是我们在实际工作中接触的最多的&#xff0c;所以有必要好好学习下&#xff01; 1&#xff1a;查询的分类 主要分为如下2类&#xff1a; 1:基于get查询参数的URI search 2&#xff1a;基于post body的request body search&am…

Netty Review - 直接内存的应用及源码分析

文章目录 Pre概述应用访问效率&#xff1a; 堆内存 VS 直接内存申请效率&#xff1a; 堆内存 VS 直接内存数据存储结构&#xff1a; 堆内存 VS 直接内存结论 ByteBuffer.allocateDirect 源码分析unsafe.allocateMemory(size) ---> C方法 JVM参数 -XX:MaxDirectMemorySize直接…

隐函数的求导【高数笔记】

1. 什么是隐函数&#xff1f; 2. 隐函数的做题步骤&#xff1f; 3. 隐函数中的复合函数求解法&#xff0c;与求导中复合函数求解法有什么不同&#xff1f; 4. 隐函数求导的过程中需要注意什么&#xff1f;

Mysql运维篇(四) Xtarbackup--备份与恢复练习

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 前言 xtrabackup是Percona公司CTO Vadim参与开发的一款基于InnoDB的在线热备工具&#xff0c;具有…