Netty学习——源码篇10 Netty内存分配ByteBuf基础

1 初始ByteBuf

        ByteBuf是Netty整个结构中最为底层的模块,主要负责把数据从底层I/O读取到ByteBuf,然后传递给应用程序,应用程序处理完成后再把数据封装成ByteBuf写回I/O。所以,ByteBuf是直接与底层打交道的一层抽象。

2 ByteBuf的基本结构

        Netty官方对ByteBuf的描述,具体如下:

        从上面ByteBuf的结构来看,发现ByteBuf有三个非常重要的指针,分别是readerIndex(记录读指针的开始位置)、writerIndex(记录写指针的开始位置)和capacity(缓冲区的总长度),三者的关系是:readerIndex <= writerIndex <= capacity。从0到readerIndex为discardable bytes,表示是无效的;从readerIndex 到 writerIndex 为readable bytes,表示可读数据区;从writerIndex 到capacity位writable bytes,表示这段区间空闲,可以往里面写数据。除了这三个指针,ByteBuf里面其实还有一个指针maxCapacity,它相当于ByteBuf扩容的最大阈值,相应代码如下。

    /**
     * Returns the maximum allowed capacity of this buffer.  If a user attempts to increase the
     * capacity of this buffer beyond the maximum capacity using {@link #capacity(int)} or
     * {@link #ensureWritable(int)}, those methods will raise an
     * {@link IllegalArgumentException}.
     */
    public abstract int maxCapacity();

        这个maxCapacity指针可以看作是指向capacity之后的这段区间,Netty发现writable bytes写数据超出空间大小时,ByteBuf会提前自动扩容,扩容之后,就有了足够的空间来写数据,同时capacity也会同步更新,maxCapacity就是扩容后capacity的最大值。

3 ByteBuf的重要API

        看一下ByteBuf的基本API,主要包括read()  write()  set()  mark() reset()等方法。请看下表

        在Netty中,ByteBuf大部分功能是在AbstractByteBuf中实现的。

public abstract class AbstractByteBuf extends ByteBuf {
    //读指针
    int readerIndex;
    //写指针
    int writerIndex;
    //mark之后的读指针
    private int markedReaderIndex;
    //mark之后的写指针
    private int markedWriterIndex;
    //最大容量
    private int maxCapacity;

    ...
}

        下面来看基本读写的骨架代码实现。例如,几个基本的判断读写区间的API,具体实现代码如下:

public abstract class AbstractByteBuf extends ByteBuf {
@Override
    public boolean isReadable() {
        return writerIndex > readerIndex;
    }

    @Override
    public boolean isReadable(int numBytes) {
        return writerIndex - readerIndex >= numBytes;
    }

    @Override
    public boolean isWritable() {
        return capacity() > writerIndex;
    }

    @Override
    public boolean isWritable(int numBytes) {
        return capacity() - writerIndex >= numBytes;
    }

    @Override
    public int readableBytes() {
        return writerIndex - readerIndex;
    }

    @Override
    public int writableBytes() {
        return capacity() - writerIndex;
    }

    @Override
    public int maxWritableBytes() {
        return maxCapacity() - writerIndex;
    }

    @Override
    public ByteBuf markReaderIndex() {
        markedReaderIndex = readerIndex;
        return this;
    }

    @Override
    public ByteBuf resetReaderIndex() {
        readerIndex(markedReaderIndex);
        return this;
    }

    @Override
    public ByteBuf markWriterIndex() {
        markedWriterIndex = writerIndex;
        return this;
    }

    @Override
    public ByteBuf resetWriterIndex() {
        writerIndex = markedWriterIndex;
        return this;
    }
}

4 ByteBuf基本分类

        AbstractByteBuf有很多子类,大致可以从三个维度进行分类。

        1、Pooled:池化内存,就是从预先分配好的内存空间中提取一段连续内存封装成一个ByteBuf,分给应用程序使用。

        2、Unsafe:是JDK底层的一个负责I/O操作的对象,可以直接获得对应的内存地址,基于内存地址进行读写操作。

        3、Direct:堆外内存,直接调用JDK底层API进行物理内存分配,不在JVM的堆内存中,需要手动释放。

        综上所述,其实ByteBuf会有6种组合:Pooled(池化内存)和Unpooled(非池化内存);Unsafe和非Unsafe;Heap(堆内存)和Direct(堆外内存)。下图是ByteBuf最重要的继承关系类结构图,通过命名就能一目了然。

        ByteBuf最基本的读写API操作在AbstractByteBuf中已经实现了,其众多子类采用不同的策略来分配内存空间,下表是对重要的几个子类的总结。

 5 ByteBufAllocator内存管理器

        Netty中内存分配有一个顶层的抽象就是ByteBufAllocator,负责分配所有ByteBuf类型的内存。主要有几个重要的API,如下表:

        以上API中为什么没有前面提到的8种类型的内存分配API?下面来看ByteBufAllocator的基本实现类AbstractByteBufAllocator,重点分析主要API的基本实现,比如buffer()方法的代码如下:

public abstract class AbstractByteBufAllocator implements ByteBufAllocator {
    public ByteBuf buffer() {
        if (directByDefault) {
            return directBuffer();
        }
        return heapBuffer();
    }
}

         发现buffer方法中对是否默认支持directBuffer做了判断,如果支持则分配directBuffer,否则分配heapBuffer。

        下面分别来看directBuffer方法和heapBuffer方法的实现,先来看directBuffer方法的代码。

    @Override
    public ByteBuf directBuffer() {
        return directBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);
    }

    @Override
    public ByteBuf directBuffer(int initialCapacity) {
        return directBuffer(initialCapacity, Integer.MAX_VALUE);
    }

    @Override
    public ByteBuf directBuffer(int initialCapacity, int maxCapacity) {
        if (initialCapacity == 0 && maxCapacity == 0) {
            return emptyBuf;
        }
        validate(initialCapacity, maxCapacity);
        return newDirectBuffer(initialCapacity, maxCapacity);
    }

        directBuffer方法有多个重载方法,最终会调用newDirectBuffer方法,下面看newDirectBuffer的代码。

protected abstract ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity);

        发现newDirectBuffer方法其实是一个抽象方法,最终,交给AbstractByteBufAllocator的子类来实现。同理再来看heapBuffer方法的代码。

   @Override
    public ByteBuf heapBuffer() {
        return heapBuffer(DEFAULT_INITIAL_CAPACITY, Integer.MAX_VALUE);
    }

    @Override
    public ByteBuf heapBuffer(int initialCapacity) {
        return heapBuffer(initialCapacity, Integer.MAX_VALUE);
    }

    @Override
    public ByteBuf heapBuffer(int initialCapacity, int maxCapacity) {
        if (initialCapacity == 0 && maxCapacity == 0) {
            return emptyBuf;
        }
        validate(initialCapacity, maxCapacity);
        return newHeapBuffer(initialCapacity, maxCapacity);
    }

        发现heapBuffer方法最终是调用newHeapBuffer方法,而newHeapBuffer方法也是抽象方法,具体交给AbstractByteBufAllocator的子类实现。AbstractByteBufAllocator的子类主要有两个:PooledByteBufAllocator和UnpooledByteBufAllocator。AbstractByteBufAllocator的子类实现的类结构图如下:

        分析到这里,已经知道directBuffer,heapBuffer和Pooled和Unpooled的分配规则,那么Unsafe和非Unsafe是如何判别的呢?其实是Netty自动判别的。如果操作系统底层支持Unsafe那就采用Unsafe读写,否则采用非Unsafe读写。可以从UnpooledByteBufAllocator的源码中验证,代码如下:

public final class UnpooledByteBufAllocator extends AbstractByteBufAllocator {

    @Override
    protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) {
        return PlatformDependent.hasUnsafe() ? new UnpooledUnsafeHeapByteBuf(this, initialCapacity, maxCapacity)
                : new UnpooledHeapByteBuf(this, initialCapacity, maxCapacity);
    }

    @Override
    protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) {
        ByteBuf buf = PlatformDependent.hasUnsafe() ?
                UnsafeByteBufUtil.newUnsafeDirectByteBuf(this, initialCapacity, maxCapacity) :
                new UnpooledDirectByteBuf(this, initialCapacity, maxCapacity);

        return disableLeakDetector ? buf : toLeakAwareBuffer(buf);
    }
}

        发现在newHeapBuffer方法和newDirectBuffer方法中,分配内存判断PlatformDependent是否支持Unsafe,如果支持则创建Unsafe类型的Buffer,否则创建非Unsafe类型的Buffer,由Netty自动判断。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机网络-HTTP相关知识-HTTPS基础

HTTP与HTTPS的区别&#xff1a; HTTPS在TCP和HTTP网络层之间加入了SSL/TLS安全协议层。这个安全协议层可以对数据进行加密&#xff0c;确保数据在传输过程中的安全。HTTPS在TCP三次握手之后&#xff0c;还需进行SSL/TLS的握手过程。这个握手过程主要是为了在客户端和服务器之间…

react16路由缓存react-activation详解

react PC端项目构建TS&#xff0c;react18.2.0antdviteaxiosreduxsassts 完整版代码下载&#xff1a; https://download.csdn.net/download/randy521520/88922625 react PC端项目构建&#xff0c;react18.2.0antdviteaxiosreduxsass完整版代码下载&#xff1a; https://downloa…

Bun 1.1 发布,全面支持 Windows 系统

4 月 2 日&#xff0c;Jarred Sumner 宣布 Bun 1.1 正式推出。Bun 是一个快速、一体化的工具包&#xff0c;用于运行、构建、测试和调试 JavaScript 和 TypeScript&#xff0c;从单个脚本到全栈应用程序。如果您是 Bun 的新手&#xff0c;可以在 Bun 1.0 博客文章中了解更多信息…

Elasticsearch 免费许可证到期问题解决

问题 es日志报错信息&#xff1a;current license is non-compliant for [security] [2024-04-01T03:20:52.96800:00][ERROR][savedobjects-service] [.kibana_alerting_cases] Action failed with security_exceptionRoot causes:security_exception: current license is no…

Spark 起源发展与项目架构说明

文章目录 前言Spark 的起源Spark 是什么速度易用性模块化可扩展性 分析方法的统一Spark SQLSpark MLlibSpark Structured StreamingGraphX Spark的分布式执行Spark driverSparkSessionCluster managerSpark executor部署模式分布式数据和分区 开发的经验Spark 的使用人群与使用…

0基础 三个月掌握C语言(16)

⽂件操作 为什么使⽤⽂件&#xff1f; 如果没有⽂件&#xff0c;我们写的程序的数据是存储在电脑的内存中&#xff0c;如果程序退出&#xff0c;内存回收&#xff0c;数据就丢失了&#xff0c;等再次运⾏程序&#xff0c;是看不到上次程序的数据的&#xff0c;如果要将数据…

成都直播产业园有哪些特色服务

在成都这片热土上&#xff0c;天府锋巢直播产业基地以其特色服务独树一帜&#xff0c;成为了引领直播行业的先锋。 一、天府锋巢直播产业基地的特色服务&#xff0c;首先体现在其完善的产业链整合能力上。 作为西南大型的成都直播产业园区&#xff0c;这里不仅汇聚了众多优秀…

js实现简单的添加移除水印效果

一、实现场景 在做某些内部管理系统时&#xff0c;需求可能要求增加水印&#xff0c;水印内容通常可能是logo或者用户名手机号。实现效果如图&#xff1a; 以下步骤可实现简单添加或者移除水印&#xff0c;并且可以自定义样式、旋转角度等。 二、实现方式 1、先新建一个js…

网络套接字补充——TCP网络编程

六、TCP网络编程 6.1IP地址字符串和整数之间的转换接口 //字符串转整数接口 #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int inet_aton(const char *cp, struct in_addr *inp); int inet_pton(int af, const char *strptr, …

Go微服务实战——服务治理(负载均衡,请求重试,服务熔断,服务降级)

负载均衡 在微服务架构中各个服务都是独立部署、可独立扩展和管理的。在上一节Go微服务实战——服务的注册与获取&#xff08;nacos做服务注册中心&#xff09;将所有的服务注册到注册中心&#xff0c;供其他服务使用。 这是对于整个系统的层面&#xff0c;对于单个服务来说&…

Linux:运营商在网络中扮演的角色

文章目录 ip目前的问题ip目前的几种解决方案私有ipVS公有ip运营商再谈ip划分运营商的角度看ip 本篇总结的是运营商在网络中扮演的角色 ip目前的问题 在目前看来&#xff0c;ip最大的问题是ip号不够用了&#xff0c;那这个问题如何解决呢&#xff1f; 在之前的内容中有子网掩…

什么是智慧公厕?智慧旅游下的智慧公厕功能和特点

智慧旅游下的智慧公厕功能和特点&#xff1f;智慧旅游是景区、公园、游乐场、文化场馆等领域的一种信息化解决方案&#xff0c;智慧公厕是智慧旅游极为重要的一部分&#xff0c;能大大提升游客满意度。智慧公厕采用物联网、互联网、大数据、云计算等技术&#xff0c;实现旅游景…

RPM与YUM

目录 rpm包的管理 介绍 rpm包的简单查询指令 rpm包名基本格式 rpm包的其他查询指令: 卸载rpm包 yum 介绍 rpm包的管理 介绍 rpm用于互联网下载包的打包及安装工具,它包含在某些Linux分发版中.它生成具有.RPM扩展名的文件.RPM是RedHat Package Manager(RedHat)软件包管…

SDWebImage源码解析---疑难问题解答

SDWebImage的简单流程图&#xff1a; 上图大致流程是对的&#xff0c;有几个没写到的地方&#xff1a; 加载沙盒中对应的图片后&#xff0c;不仅要显示&#xff0c;而且要把图片缓存到内存中下载完毕后&#xff0c;有一个异步解码的过程&#xff0c;没体现出来 网上有大佬做了…

修改nuxtjs项目中的浏览器图标步骤

处理步骤&#xff1a; 打开配置页面 使用el-upload 上传图片到后台 后台把图片转为ico&#xff0c;返回图标路径 配置页面修改本页面预览图&#xff0c;点击保存&#xff0c;修改的数据库。 通知nuxt布局页面&#xff0c;修改head节点中的图标属性&#xff0c;…

智慧酒店(二):AI智能分析网关V4视频分析技术在酒店管理中的应用

一、人工智能技术如何应用在酒店管理中&#xff1f; 随着科技的飞速发展&#xff0c;人工智能技术已经逐渐渗透到我们生活的方方面面&#xff0c;其中&#xff0c;酒店管理行业便是其应用的重要领域之一。人工智能技术以其高效、精准的特点&#xff0c;为酒店管理带来了革命性…

基于java的智能停车场管理系统

开发语言&#xff1a;Java 框架&#xff1a;ssm 技术&#xff1a;JSP JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclip…

文件管理原理

文章目录 1)一个文件&#xff0c;它是文件内容和文件属性的集合 文件文件属性文件内容 文件属性 文件内容 2)文件分为打开的文件和未打开的文件 3)打开的文件是谁打开的&#xff1f; 由进程打开&#xff01;而研究一个被打开的进程本质就是研究进程和文件的关系。 而被打开的…

vue快速入门(二)安装vue调试插件

教程很详细&#xff0c;直接上过程 上一篇 新增内容 在国内网站下载谷歌插件安装插件 点击跳转极简插件 此处我们以Chrome浏览器为例 到这里我们就成功安装了插件 使用上一篇博客的代码在浏览器F12调试一下 这样就可以使用了&#xff01;&#xff01;&#xff01;

依赖倒转原则

1.1 MM请求电脑 MM电脑坏了&#xff0c;需要修电脑&#xff0c;是因为每次打开QQ,一玩游戏&#xff0c;机器就死了。出来蓝底白字的一堆莫名奇妙的英文。蓝屏死机了&#xff0c;估计内存有问题。 1.2 电话遥控修电脑 遥控修理电脑&#xff0c;打开内存条&#xff0c;两根内存…