Buffer和ByteBuffer和ByteBuf有什么区别?

Buffer、ByteBuffer 和 ByteBuf 都是处理数据缓冲的核心类,但它们来自不同的库,设计目标和功能特性有明显差异。

Buffer(Java NIO)
定义:Buffer是Java NIO(New Input/Output)中的一个抽象类,用于表示一个字节序列的缓冲区。它是所有缓冲区类的父类,子类包括 ByteBuffer、CharBuffer、IntBuffer 等,分别处理不同类型的数据,提供了对字节数据的读写操作。
特性
固定容量:创建时指定容量,不可动态扩展。
读写模式切换:通过 flip()、clear()、compact() 等方法切换读写模式。
直接内存支持:通过 allocateDirect() 分配堆外内存(避免 JVM 堆与本地内存的拷贝)。
局限性
读写索引共用 position,需频繁切换模式,容易出错。
API 功能较为基础,缺少高级操作(如自动扩容、复合缓冲区)。

ByteBuffer(Java NIO)
ByteBuffer是Buffer 的子类,专门处理字节数据,是 Java NIO 的核心组件。
特性
直接操作字节:提供 get()、put() 等方法读写字节。
堆内存与堆外内存:
allocate():分配堆内存(JVM 管理)。
allocateDirect():分配堆外内存(由操作系统管理,减少拷贝开销)。
视图缓冲区:支持生成只读缓冲区或分片(slice()、asReadOnlyBuffer())。
局限性
固定容量:无法动态扩容,需手动管理空间。
读写切换繁琐:每次读写后需调用 flip() 或 rewind() 重置指针。
功能受限:缺少复合缓冲区、引用计数等高级特性。

ByteBuf(Netty)
ByteBuf是Netty框架中的一个类,用于表示一个字节缓冲区。它是Netty中处理字节数据的核心组件,提供了比Java标准库中的ByteBuffer更灵活和强大的功能。
核心改进
读写索引分离:readerIndex 和 writerIndex 分开,无需调用 flip()。
动态扩容:写入数据时自动扩展容量(可配置阈值)。
内存池化:支持基于内存池的分配(PooledByteBuf),减少内存分配开销。
复合缓冲区:通过 CompositeByteBuf 将多个 ByteBuf 逻辑合并,避免内存拷贝。
引用计数:基于 ReferenceCounted 接口实现内存的自动释放(类似 C++ 的智能指针)。
零拷贝支持:通过 slice()、duplicate() 共享数据,避免拷贝。

内存类型
堆内存(HeapByteBuf):由 JVM 管理。
堆外内存(DirectByteBuf):由操作系统管理,适合网络 I/O。
优势场景
高频读写操作(如网络通信)。
需要高性能内存管理(如高并发服务器)。

  • 主要区别

读写模式
Buffer:作为抽象类,定义了缓冲区的通用行为,读写模式的具体实现依赖于其子类。
ByteBuffer:使用单一的position指针来跟踪读写的位置。在读写模式切换时,需要调用flip方法将position重置为0,并将limit设置为之前的position值。在写操作之前,通常需要调用clear方法来准备缓冲区。
ByteBuf:使用两个独立的指针,readerIndex和writerIndex,分别跟踪读和写的位置。这种设计允许读写操作并发进行,无需模式切换。

扩容支持
Buffer:抽象类本身不支持动态扩容。
ByteBuffer:一旦分配完成,容量固定,无法自动扩展。
ByteBuf:支持动态扩容。当数据超出当前容量时,ByteBuf会自动分配一个新的、更大的字节数组,并将旧数组的内容复制到新数组中。

池化机制
Buffer:抽象类本身不包含池化机制。
ByteBuffer:没有内置的内存池化机制。每次分配和释放都需要系统调用。
ByteBuf:内置内存池化机制(如PooledByteBufAllocator),优化了内存分配和回收效率。这有助于减少内存碎片和垃圾回收的开销。

引用计数
Buffer:抽象类本身不支持引用计数。
ByteBuffer:不支持引用计数。生命周期需要开发者手动管理。
ByteBuf:支持引用计数(retain()、release()),可以自动管理缓冲区的生命周期。这有助于避免内存泄漏和重复释放内存的问题。

零拷贝特性
Buffer:抽象类本身不包含零拷贝特性。
ByteBuffer:支持基础的零拷贝操作,如slice()和duplicate()。
ByteBuf:支持更高级的零拷贝功能,如slice和复合缓冲区(CompositeByteBuf)。这些操作可以在不复制数据的情况下有效地处理数据,从而减少了CPU的负担和内存的消耗。

在这里插入图片描述

ByteBuffer底层原理
内存分配:ByteBuffer 的底层是一个连续的字节数组,可以分配在 JVM 堆内存 或 直接内存(堆外内存),堆内存(Heap ByteBuffer):通过 ByteBuffer.allocate(int capacity) 分配,数据存储在 JVM 堆中,受垃圾回收(GC)管理。
直接内存(Direct ByteBuffer):通过 ByteBuffer.allocateDirect(int capacity) 分配,数据存储在操作系统的本地内存中,通过 DirectByteBuffer 类实现,避免了 JVM 堆与本地内存之间的数据拷贝(适合高频 I/O 操作)。
指针管理:ByteBuffer内部使用几个关键的指针(或索引)来管理数据的读写位置,包括position(当前位置)、limit(限制位置)和capacity(容量)。这些指针共同决定了数据的可读、可写范围。
读写模式切换:ByteBuffer支持读写模式的切换。在写模式下,数据被写入缓冲区;在读模式下,数据从缓冲区被读取。flip()方法用于从写模式切换到读模式,而clear()方法则用于从读模式切换回写模式。
核心概念
容量(Capacity):ByteBuffer的总大小,即它可以容纳的最大字节数。一旦分配,容量就不能改变。如果需要更大的缓冲区,只能创建一个新的ByteBuffer对象。
限制(Limit):当前可以进行读写操作的最大位置。在写模式下,limit等于capacity;在读模式下,limit等于之前写入的字节数(flip()方法设置)。
当前位置(Position):下一个要读或写的元素的索引。初始值为0。每进行一次读写操作,position都会相应增加。
标记(Mark):一个可选的标记位置,可以通过mark()方法设置,通过reset()方法恢复到标记位置。这允许在读取数据时能够回退到之前的一个点。
剩余空间(Remaining):当前position和limit之间的元素数量,表示还可以进行多少次的读写操作。
在这里插入图片描述

// 分配堆内存 ByteBuffer(容量 10)
ByteBuffer buffer = ByteBuffer.allocate(10);

// 写入数据
buffer.put((byte) 1);   // position=1
buffer.put((byte) 2);   // position=2
buffer.put((byte) 3);   // position=3

// 切换为读模式
buffer.flip();          // position=0, limit=3

// 读取数据
while (buffer.hasRemaining()) {
    System.out.println(buffer.get());  // 依次输出 1, 2, 3
}

// 清空缓冲区(切换回写模式)
buffer.clear();         // position=0, limit=10

// 分配直接内存 ByteBuffer(容量 4)
ByteBuffer directBuffer = ByteBuffer.allocateDirect(4);

// 设置字节序为 Little-Endian
directBuffer.order(ByteOrder.LITTLE_ENDIAN);

// 写入一个 int 值(0x12345678)
directBuffer.putInt(0x12345678);  // 按 Little-Endian 存储为 [0x78, 0x56, 0x34, 0x12]

// 读取验证
directBuffer.flip();
System.out.printf("0x%08x", directBuffer.getInt());  // 输出 0x12345678(自动转换字节序)
// 分配一个容量为 10 的 ByteBuf(Netty)
ByteBuf buffer = Unpooled.buffer(10);

// 写入数据(无需切换模式)
buffer.writeByte(1);
buffer.writeByte(2);

// 读取数据
while (buffer.isReadable()) {
    System.out.println(buffer.readByte());
}

// 释放内存(若使用池化内存)
buffer.release();
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值