Netty Review - ByteBuf内存池源码解析

news2024/11/22 13:49:24

文章目录

  • 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/2254
        if (!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) { // 如果初始容量和最大容量都为0
        return 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);
    // 使用指定的线程缓存和请求容量来分配内存给 ByteBuf
    allocate(cache, buf, reqCapacity);
    // 返回分配的 ByteBuf
    return buf;
}

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

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

在这里插入图片描述

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

@Override
protected PooledByteBuf<ByteBuffer> newByteBuf(int maxCapacity) {
    // 如果支持 Unsafe
    if (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.coloradmin.cn/o/1452347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二叉树入门算法题详解

二叉树入门题目详解 首先知道二叉树是什么&#xff1a; 代码随想录 (programmercarl.com) 了解后知道其实二叉树就是特殊的链表&#xff0c;只是每个根节点节点都与两个子节点相连而其实图也是特殊的链表&#xff0c;是很多节点互相连接&#xff1b;这样说只是便于理解和定义…

Sora技术报告——Video generation models as world simulators

文章目录 1. 视频生成模型&#xff0c;可以视为一个世界模拟器2. 技术内容2.1 将可视数据转换成patches2.2 视频压缩网络2.3 Spacetime Latent Patches2.4 Scaling transformers 用于视频生成2.5 可变的持续时间&#xff0c;分辨率&#xff0c;宽高比2.6 抽样的灵活性2.7 改进框…

软件工程师,OpenAI Sora驾到,快来围观

概述 近期&#xff0c;OpenAI在其官方网站上公布了Sora文生视频模型的详细信息&#xff0c;展示了其令人印象深刻的能力&#xff0c;包括根据文本输入快速生成长达一分钟的高清视频。Sora的强大之处在于其能够根据文本描述&#xff0c;生成长达60秒的视频&#xff0c;其中包含&…

【教学类-19-09】20240214《ABAB式-规律黏贴18格-手工纸15*15CM-一页3种图案,AB满,纵向、无边框》(中班)

背景需求 利用15*15CM手工纸制作AB色块手环&#xff08;手工纸自带色彩&#xff09;&#xff0c;一页3个图案&#xff0c;2条为一组&#xff0c;黏贴成一个手环 素材准备 代码展示 # # 作者&#xff1a;阿夏 # 时间&#xff1a;2024年2月14日 # 名称&#xff1a;正方形数字卡…

普中51单片机学习(二)

51单片机介绍 所需基础知识 基础数模电知识&#xff0c;简单的C语言。 PS&#xff1a;如果有不懂的直接通义千问。。。 什么是单片机 在一片集成电路芯片上集成微处理器、存储器、I/O接口电路&#xff0c;从而构成了单芯片微型计算机&#xff0c;即单片机。 学习方法 多实…

LaTeX中的documentclass命令:指定文档的类型和整体布局

诸神缄默不语-个人CSDN博文目录 documentclass 是 LaTeX 中一个基础且重要的命令&#xff0c;用于定义文档的整体布局和样式。这个命令告诉 LaTeX 编译器文档是属于哪一类的&#xff0c;比如是文章、报告、书籍等&#xff0c;每一类都有其预定义的格式和结构。 文章目录 基本语…

Linux常见指令(一)

一、基本指令 1.1ls指令 语法 &#xff1a; ls [ 选项 ][ 目录或文件 ] 功能&#xff1a;对于目录&#xff0c;该命令列出该目录下的所有子目录与文件。对于文件&#xff0c;将列出文件名以及其他信息。 常用选项&#xff1a; -a 列出目录下的所有文件&#xff0c;包括以 .…

LeetCode 100题目(python版本)待续...

一.哈希 1.两数之和 题目 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复…

一个小白的转行Python的经历!

1. 寻找一个导师 导师可以降低你加入一个新行业的成本&#xff0c;帮助你熟悉环境和行业规则&#xff0c;也会鼓励你完成心理方面的转变。 2. 建立新的社交网络 过去的人脉关系会阻碍你的转行&#xff0c;因为他们是以过去对你的认知来评价你。新领域的人脉&#xff0c;会给你提…

HAL库 STM32驱动W25QXX驱动例程

HAL库 STM32驱动W25QXX驱动例程 &#x1f4cd;驱动程序参考&#xff1a;《STM32CubeMX | 基于STM32使用HAL库W25Q128驱动程序》&#x1f511; 驱动方式&#xff1a;硬件SPI方式和SPI DMA方式。&#x1f516;适用于&#xff1a;W25X系列/Q系列芯片:W25Q80、W25Q16、W25Q32、 W25…

rust函数 stuct struct方法 关联函数

本文结合2个代码实例主要介绍了rust函数定义方法&#xff0c;struct结构体定义、struct方法及关联函数等相关基础知识。 代码1&#xff1a; main.rc #[derive(Debug)]//定义一个结构体 struct Ellipse {max_semi_axis: u32,min_semi_axis: u32, }fn main() {//椭圆&#xff0…

第14集《佛说四十二章经》

好&#xff01;请大家打开讲义第十九面&#xff0c;第三十九章、教诲无差。 佛言&#xff1a;学佛道者&#xff0c;佛所言说&#xff0c;皆应信顺。譬如食蜜&#xff0c;中边皆甜。吾经亦尔。 大智慧的佛陀说&#xff0c;佛弟子们在修学过程中&#xff0c;对佛陀所说的一切佛…

面向对象编程(一)

目录 1. 面向对象编程概述(了解) 1.1 程序设计的思路 1.2 由实际问题考虑如何设计程序 2. Java语言的基本元素&#xff1a;类和对象 2.1 类和对象概述 2.2 类的成员概述 2.3面向对象完成功能的三步骤&#xff08;重要&#xff09; 步骤1&#xff1a;类的定义 步骤2&#xff1a;…

什么是数据同步利器DataX,如何使用?

转载至我的博客 https://www.infrastack.cn &#xff0c;公众号&#xff1a;架构成长指南 今天给大家分享一个阿里开源的数据同步工具DataX&#xff0c;在Github拥有14.8k的star&#xff0c;非常受欢迎&#xff0c;官网地址&#xff1a;https://github.com/alibaba/DataX 什么…

c++类和对象新手保姆级上手教学(上)

前言&#xff1a; c其实顾名思义就是c语言的升级版&#xff0c;很多刚学c的同学第一感觉就是比c语言难学很多&#xff0c;其实没错&#xff0c;c里的知识更加难以理解可以说杂且抽象&#xff0c;光是类和对象&#xff0c;看起来容易&#xff0c;但想完全吃透&#xff0c;真的挺…

(免费领源码)java#springboot#mysql医院自助服务系统74853-计算机毕业设计项目选题推荐

目 录 摘要 1 绪论 1.1研究意义 1.2研究背景 1.3springboot框架介绍 1.3论文结构与章节安排 2 医院自助服务系统系统分析 2.1 可行性分析 2.2 系统流程分析 2.2.1 数据流程 3.3.2 业务流程 2.3 系统功能分析 2.3.1 功能性分析 2.3.2 非功能性分析 2.4 系统用例分…

java+springboot+vue试题库在线学习系统05umj

技术路线&#xff1a; B/S架构&#xff0c;后端springboot框架&#xff0c;前端Vue.js框架。 主要功能模块&#xff08;至少六大功能&#xff09;&#xff0c;参考任务书并拓展 &#xff08;1&#xff09;用户管理模块&#xff1a;规定不同角色的用户对系统中各个功能模块的使用…

【学网攻】 第(29)节 -- 综合实验二

系列文章目录 目录 系列文章目录 文章目录 前言 一、综合实验 二、实验 1.引入 实验目标 实验设备 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻】 第(2)节 -- 交换机认识及使用【学网攻】 第(3)节 -- 交换机配置聚合端口【学网攻…

【Make编译控制 06】CMake初步使用

目录 一、概述与安装 二、编译源文件 三、无关文件管理 一、概述与安装 CMake是一个跨平台的项目构建工具&#xff0c;相比于Makefile&#xff0c;CMake更加高级&#xff0c;因为CMake代码在执行的时候是会先翻译生成Makefile文件&#xff0c;再调用Makefile文件完成项目构…

【Python--网络编程之TCP三次握手】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;Python开发技术 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; Python网络编程之[TCP三次握手] 往期内容代码见资源&#xff0c;效果图如下一、实验要求二、协…