学习Netty(五)------ByteBuf 的设计和使用

前言

为了方便大家理解,我每个文章都会画出逻辑图,以方便大家理解,大家可以结合着图来进行学习
在这里插入图片描述

ByteBuf 的概念

ByteBuf 是 Netty 中用于处理字节数据的缓冲区类。与传统的字节数组(byte array)相比,ByteBuf 提供了更为灵活、高效的 API,并且在处理大量数据时具有更好的性能。

1 读写索引分离

ByteBuf 支持读索引(readerIndex)和写索引(writerIndex)的分离,允许并发地进行读写操作。这意味着可以同时从缓冲区读取数据和向缓冲区写入数据,而不需要进行额外的同步。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class ByteBufExample {
    public static void main(String[] args) {
        // 创建一个堆内存的 ByteBuf,初始容量为10
        ByteBuf byteBuf = Unpooled.buffer(10);

        // 向 ByteBuf 写入数据
        byteBuf.writeBytes("Hello".getBytes());

        // 打印原始数据
        System.out.println("Original ByteBuf: " + byteBuf.toString());

        // 读取数据
        int readableBytes = byteBuf.readableBytes();
        byte[] result = new byte[readableBytes];
        byteBuf.readBytes(result);

        // 打印读取的数据
        System.out.println("Read Data: " + new String(result));

        // 打印读取后的 ByteBuf
        System.out.println("Updated ByteBuf: " + byteBuf.toString());
    }
}

2 可动态扩容

ByteBuf 可以根据需要自动扩容,避免了在处理不确定大小的数据时频繁进行手动扩容的操作。这使得 ByteBuf 在处理各种大小的数据时表现更为灵活。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;

public class DynamicExpansionExample {
    public static void main(String[] args) {
        // 创建一个堆内存的 ByteBuf,初始容量为4
        ByteBuf byteBuf = Unpooled.buffer(4);

        // 打印初始容量和写入数据前的 ByteBuf 信息
        System.out.println("Initial Capacity: " + byteBuf.capacity());
        System.out.println("Original ByteBuf: " + byteBuf.toString());

        // 向 ByteBuf 写入超过初始容量的数据
        byteBuf.writeBytes("Hello, Netty!".getBytes());

        // 打印写入后的 ByteBuf 信息
        System.out.println("Updated ByteBuf: " + byteBuf.toString());
        System.out.println("New Capacity: " + byteBuf.capacity());
    }
}

3 支持 Composite 模式

ByteBuf 可以由多个子缓冲区组成,形成一个复合缓冲区,称为 CompositeByteBuf。这种设计使得可以有效地处理复杂的数据结构,同时避免不必要的数据拷贝。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.CompositeByteBuf;
import io.netty.buffer.Unpooled;
//Netty 中的 ByteBuf 支持 Composite 模式,即一个 ByteBuf 可以由多个子缓冲区组成,形成一个复合缓冲区。
//这种设计在处理复杂的数据结构时非常有用,可以避免不必要的数据拷贝,提高性能。以下是一个简单的示例代码,演示了如何使用 CompositeByteBuf 创建一个复合缓冲区:
public class CompositeByteBufExample {
    public static void main(String[] args) {
        // 创建两个堆内存的 ByteBuf,分别存储 "Hello, " 和 "Netty!"
        ByteBuf buf1 = Unpooled.copiedBuffer("Hello, ".getBytes());
        ByteBuf buf2 = Unpooled.copiedBuffer("Netty!".getBytes());

        // 创建一个 CompositeByteBuf,将两个 ByteBuf 合并
        CompositeByteBuf compositeBuf = Unpooled.compositeBuffer();
        compositeBuf.addComponents(buf1, buf2);

        // 打印 CompositeByteBuf 信息
        System.out.println("Composite ByteBuf: " + compositeBuf.toString());

        // 释放资源
        compositeBuf.release();
    }
}

4 内存池化支持

Netty 中的 ByteBuf 提供了内存池化的支持。通过对分配的内存进行池化管理,可以减少内存碎片,提高内存的利用率,并降低内存分配的开销,从而提高系统的性能。

import io.netty.buffer.ByteBuf;
import io.netty.buffer.PooledByteBufAllocator;
//netty 中的 ByteBuf 内存池化是通过 PooledByteBufAllocator 实现的,它提供了对内存的池化管理,可以有效地重用内存,降低内存分配和释放的开销。以下是一个简单的示例代码,演示了如何使用内存池化的 ByteBuf:
public class PooledByteBufExample {
    public static void main(String[] args) {
        // 使用默认的内存池分配器
        PooledByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT;

        // 从内存池中分配一个 ByteBuf,初始容量为10
        ByteBuf byteBuf = allocator.heapBuffer(10);

        // 打印 ByteBuf 信息
        System.out.println("Pooled ByteBuf: " + byteBuf.toString());

        // 释放资源,归还给内存池
        byteBuf.release();
    }
}
//在这个示例中,使用了默认的内存池分配器 PooledByteBufAllocator,通过调用 heapBuffer 方法从内存池中分配一个初始容量为 10 的 ByteBuf。最后,通过 release 方法将 ByteBuf 的资源释放,归还给内存池。

内存分配方式

1.堆内存

堆内存使用 Java 堆进行内存分配。它的优势在于分配和释放的成本相对较低,适用于小型数据和频繁的分配与释放场景。

// 创建一个堆内存的 ByteBuf,初始容量为10
ByteBuf heapBuffer = Unpooled.buffer(10);

2.直接内存

直接内存使用操作系统的本地 I/O 操作进行内存分配。尽管分配和释放的成本较高,但在数据传输时,可以避免数据在 Java 堆和本地内存之间的拷贝,提高传输性能。

// 创建一个直接内存的 ByteBuf,初始容量为10
ByteBuf directBuffer = Unpooled.directBuffer(10);

使用示例

以下是一个简单的 ByteBuf 使用示例:

public class ByteBuf{
    public static void main(String[] args) {
            // 创建一个初始容量为10的堆内存 ByteBuf
            ByteBuf heapBuffer = Unpooled.buffer(10);
            // 创建一个初始容量为10的直接内存 ByteBuf
            ByteBuf directBuffer = Unpooled.directBuffer(10);
            //写数据
            ByteBuf byteBuf = Unpooled.buffer(10);
            byteBuf.writeBytes("Hello, Netty!".getBytes());
            //读数据
            int readableBytes = byteBuf.readableBytes();
            byte[] result = new byte[readableBytes];
            byteBuf.readBytes(result);
            //动态扩容
            ByteBuf dynamicBuffer = Unpooled.buffer(4);
            dynamicBuffer.writeBytes("Hello, Netty!".getBytes());
            //Composite 模式
            ByteBuf buf1 = Unpooled.copiedBuffer("Hello, ".getBytes());
            ByteBuf buf2 = Unpooled.copiedBuffer("Netty!".getBytes());
            CompositeByteBuf compositeBuf = Unpooled.compositeBuffer();
            compositeBuf.addComponents(buf1, buf2);
            //引用计数
            ByteBuf refCountedBuf = Unpooled.buffer(10);
            refCountedBuf.retain(); // 引用计数加一
            refCountedBuf.release(); // 引用计数减一
            //池化
            PooledByteBufAllocator allocator = PooledByteBufAllocator.DEFAULT;
            ByteBuf pooledBuffer = allocator.heapBuffer(10);
            // 读写索引分离
            byteBuf = Unpooled.buffer(10);
            byteBuf.writeBytes("Hello".getBytes());
            // 读取数据
            readableBytes = byteBuf.readableBytes();
            result = new byte[readableBytes];
            byteBuf.readBytes(result);
            //ByteBuf 的状态和信息
            int capacity = byteBuf.capacity(); // 获取容量
            readableBytes = byteBuf.readableBytes(); // 获取可读字节数
            int writableBytes = byteBuf.writableBytes(); // 获取可写字节数
            boolean isDirect = byteBuf.isDirect(); // 判断是否为直接内存
            //释放资源
            byteBuf.release();
        }
}

总结

ByteBuf 在 Netty 中扮演着重要的角色,为开发者提供了强大的工具来处理字节数据,尤其在高性能网络编程中发挥着不可替代的作用。深入理解 ByteBuf 的使用方法和特性,能够更好地发挥 Netty 在网络通信中的优势。

这里我只做了简单介绍,netty是一个庞大的架构,之后的文章我会分开模块对其进行分析
这里作为目录方便大家学习(后续持续更新中):
学习netty-通俗易懂版本
学习Netty(一)------Netty 架构概览
学习Netty(二)------Netty 启动过程与初始化
学习Netty(三)------Channel 和 EventLoop
学习Netty(四)------ChannelPipeline 和 ChannelHandler
学习Netty(五)------ByteBuf 的设计和使用
学习Netty(六)------编解码器的实现
学习Netty(七)------Selector 和事件模型
学习Netty(八)------性能优化和底层实现细节
学习Netty(九)------代码实现
学习Netty(十)------高级功能和扩展

  • 14
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值