Netty源码分析---Java-NIO-ByteBuffer核心详解-简化版

Netty的ByteBuf相比JDK的ByteBuffer有什么优势? 痛点1:固定容量困境// ByteBuffer的典型创建方式// 容量固定为1024字节// 当需要写入超过1024字节的数据时,必须手动处理// 缓冲区已满,必须执行IO操作刷新数据// 重置缓冲区状态这种固定容量设计在处理动态大小数据时极为不便,迫使开发者编写复杂的分块逻辑,增加了代码复杂度和出错风险。痛点2:位置指针管理的复杂性ByteBuffer使用单一position指针跟踪当前操作位置,读写切换时必须手动调用flip()rewind()或clear() 阅读详情

Java NIO ByteBuffer 核心详解(简化版)

为学习 Netty ByteBuf 打基础

一、为什么需要 ByteBuffer?

网络编程中,数据以字节为单位传输。如果每次都直接操作网络 IO,性能会很低。

解决方案:使用缓冲区(Buffer)

  • 先把数据放入内存缓冲区
  • 批量读写,减少 IO 次数
  • 大幅提升性能

问题:Java NIO 的 ByteBuffer 使用复杂,所以 Netty 自己实现了 ByteBuf。


二、ByteBuffer 核心概念

ByteBuffer 就像一个可读可写的数组,但需要手动管理读写位置。

2.1 四个核心属性

0 <= mark <= position <= limit <= capacity
属性作用
capacity缓冲区总容量(固定不变)
position当前读/写位置(会移动)
limit可读/可写的边界
mark标记位置(用于回退,可选)

三、两种模式对比

3.1 写入模式(初始状态)

创建: ByteBuffer buffer = ByteBuffer.allocate(6);

[_][_][_][_][_][_]
 ↑              ↑
position=0   limit=capacity=6

写入 3 个字节后:
[A][B][C][_][_][_]
          ↑     ↑
     position=3 limit=6

写入模式特点:

  • position:下一个要写入的位置
  • limit:最多能写到哪里(= capacity)
  • capacity:总容量

3.2 读取模式(调用 flip() 后)

buffer.flip();  // 切换到读取模式

[A][B][C][_][_][_]
 ↑        ↑     ↑
position=0 limit=3 capacity=6

读取模式特点:

  • position:下一个要读取的位置(重置为 0)
  • limit:可读数据的边界(= 之前的 position)
  • capacity:总容量不变

四、核心方法详解

4.1 flip() - 写转读

public final Buffer flip() {
    limit = position;      // 限制读取范围
    position = 0;          // 从头开始读
    mark = -1;
    return this;
}

使用场景:写完数据后,准备读取

4.2 clear() - 清空重用

public final Buffer clear() {
    position = 0;
    limit = capacity;
    mark = -1;
    return this;
}

注意:

  • 数据并未真正清除
  • 只是重置指针,准备重新写入
  • 未读数据会被覆盖

4.3 compact() - 压缩未读数据

// 将未读数据移到开头,继续写入
public ByteBuffer compact() {
    int remaining = limit - position;  // 未读数据量
    // 将未读数据复制到开头
    System.arraycopy(array, position, array, 0, remaining);
    position = remaining;
    limit = capacity;
    return this;
}

使用场景:

  • 还有未读数据
  • 但需要继续写入新数据
  • 不想丢弃未读数据

五、实战示例

5.1 完整读写流程

public class ByteBufferSimpleDemo {
    public static void main(String[] args) {
        // 1. 创建缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(10);
        System.out.println("初始: " + buffer);  
        // 输出: pos=0 lim=10 cap=10
        
        // 2. 写入数据
        buffer.put("ABCD".getBytes());
        System.out.println("写入后: " + buffer);  
        // 输出: pos=4 lim=10 cap=10
        
        // 3. 切换到读模式
        buffer.flip();
        System.out.println("flip后: " + buffer);  
        // 输出: pos=0 lim=4 cap=10
        
        // 4. 读取数据
        byte[] data = new byte[buffer.limit()];
        buffer.get(data);
        System.out.println("读取: " + new String(data));  
        // 输出: ABCD
        System.out.println("读取后: " + buffer);  
        // 输出: pos=4 lim=4 cap=10
        
        // 5. 清空重用
        buffer.clear();
        System.out.println("clear后: " + buffer);  
        // 输出: pos=0 lim=10 cap=10
    }
}

5.2 compact() 使用场景

public class CompactDemo {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(10);
        
        // 写入 5 个字节
        buffer.put("ABCDE".getBytes());
        System.out.println("写入: " + buffer);  
        // pos=5 lim=10 cap=10
        
        // 切换到读模式
        buffer.flip();
        System.out.println("flip: " + buffer);  
        // pos=0 lim=5 cap=10
        
        // 只读取 2 个字节
        byte[] temp = new byte[2];
        buffer.get(temp);
        System.out.println("读取2字节: " + new String(temp));  
        // 输出: AB
        System.out.println("读取后: " + buffer);  
        // pos=2 lim=5 cap=10 (还有CDE未读)
        
        // 使用 compact 保留未读数据
        buffer.compact();
        System.out.println("compact: " + buffer);  
        // pos=3 lim=10 cap=10
        // 内部: [C][D][E][_][_][_][_][_][_][_]
        
        // 继续写入新数据
        buffer.put("FG".getBytes());
        System.out.println("继续写: " + buffer);  
        // pos=5 lim=10 cap=10
        // 内部: [C][D][E][F][G][_][_][_][_][_]
    }
}

六、常见使用模式

6.1 NIO 服务器读写示例

// 读取客户端数据
if (key.isReadable()) {
    SocketChannel client = (SocketChannel) key.channel();
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    
    // 从 channel 读取数据到 buffer(写入模式)
    int bytesRead = client.read(buffer);
    
    if (bytesRead > 0) {
        // 切换到读模式
        buffer.flip();
        
        // 处理数据
        byte[] data = new byte[buffer.limit()];
        buffer.get(data);
        System.out.println("收到: " + new String(data));
        
        // 准备回写
        buffer.clear();
        buffer.put("响应数据".getBytes());
        buffer.flip();
        
        // 写回客户端
        client.write(buffer);
    }
}

七、核心要点总结

7.1 记住这个流程

1. allocate()  → 创建缓冲区(写模式)
2. put()       → 写入数据
3. flip()      → 切换到读模式
4. get()       → 读取数据
5. clear()     → 清空,准备重新写入
   或 compact() → 保留未读数据,继续写入

7.2 模式切换对比表

操作positionlimit说明
初始/clear()0capacity写模式
写入数据递增capacity写模式
flip()0旧position读模式
读取数据递增不变读模式
compact()未读数据量capacity写模式

7.3 方法选择

  • clear():读完所有数据,准备重新写入
  • compact():还有未读数据,但要继续写入
  • flip():写完数据,准备读取

八、ByteBuffer 的问题

虽然 ByteBuffer 功能完整,但存在以下问题:

  1. 读写模式需要手动切换(flip/clear/compact)
  2. 容量固定,无法动态扩展
  3. API 不够友好,容易出错
  4. 只有一个 position,不能同时读写

这就是 Netty 为什么要实现 ByteBuf 的原因!

ByteBuf 的优势:

  • 读写索引分离(readerIndex / writerIndex)
  • 自动扩容
  • 零拷贝支持
  • 引用计数管理内存
  • 链式调用,API 更友好

下一步:学习 Netty ByteBuf 的实现原理和使用方式

Bytebuffer源码剖析及实现原理 Bytebuffer 官方解释A byte buffer,一个字节缓冲区。 一. 使用方法 ByteBuffer 初始状态是写模式, 使用IO流即可写入数据,如: channel.read() 如果需要读取ByteBuffer中的数据调用filp()方法切换即可 从ByteBuffer中读取数据有很多API 最常用的有 ByteBuffer.get()方法 读取完成之后调用 clear()或者compact()切换至写模式 日常使用中重复 1~4步骤以节省服务器内存空间 二. Byt 阅读详情

相关推荐

全志V3S开发板实战:从零构建嵌入式Linux系统

本文提供了一份针对全志V3S开发板(如LicheePi Zero)的零基础教程,详细指导如何从零开始构建嵌入式Linux系统。内容涵盖编译环境搭建、交叉工具链配置、U-Boot引导程序编译与烧录、Linux内核定制与编译,以及使用Buildroot构建根文件系统,最终实现系统成功启动,帮助开发者深入理解嵌入式系统构建全流程。

tensor9flow的博客 575

【Netty源码解读和权威指南】第11篇:Netty ByteBuf全解析(上)—— 告别NIO ByteBuffer的痛,Netty缓冲区就是这么香

本文深入解析了Netty ByteBuf缓冲区相比NIO ByteBuffer的显著优势。首先通过一个线上事故案例,揭示了NIO ByteBuffer读写指针共用、状态切换繁琐等"七宗罪"。然后详细对比了ByteBuf的核心改进:读写指针分离设计、自动扩容机制和丰富API。通过代码示例展示了ByteBuf的创建、读写操作,突出其无需flip()切换的便捷性。文章采用技术对比和实际案例相结合的方式,帮助开发者理解ByteBuf的设计哲学和正确使用方法。

xyghehehehe的专栏 361

Zemax实战:20×超高清变焦镜头设计全流程解析(从架构到制造)

本文详细解析了使用Zemax软件设计一款20倍变焦比、恒定F2.8光圈8K超高清镜头的全流程。从应对恒定光圈、宽光谱与8K解析力三大挑战的初始架构规划,到构建多重组态模型、分七阶段进行像差优化与公差分析,最终跨越制造鸿沟,为广播级影视与高精度工业检测应用提供了实战指南。

sun99的博客 552

Java NIO高频面试题解析:ByteBuffer如何正确实现读写模式切换(含源码分析)

掌握Java NIO ByteBuffer读写模式切换技巧,解决通道读写错乱问题。详解flip()、clear()和compact()方法在文件传输与网络通信中的应用,提升缓冲区操作效率,避免数据丢失。源码解析助你深入理解机制,值得收藏。

CodeWhim的博客 678

FLUKA软件在Ubuntu的安装指南(亲测有效)

FLUKA其强大的蒙特卡洛模拟能力使得用户能够模拟复杂的辐射相互作用过程

chencheng1127的博客 2887

OpenCV实战:5分钟搞定图像拼接(附Python代码)

本文通过OpenCV实战教程,详细讲解如何使用Python在5分钟内完成图像拼接。重点介绍`findHomography`函数和单应性矩阵的应用,提供完整的代码示例和常见问题解决方案,帮助开发者快速掌握图像拼接技术。

weixin_26833503的博客 121

Netty 源码分析之 Java NIO

Java NIO(新的IO)是Java(来自Java 1.4)的可选IO API,意味着可选标准Java IO和Java连网API。Java NIO提供了一种不同于标准IO API的IO工作方式。为什么会出现 Java NIO 呢?下面我们来比较一下 Java IO 也 JDK 1.4 之后出现的 Java NIO 有什么区别. 1、IO 与 NIO 下面就是 IO 与 NIO 的对比: IO NIO 面向流 面向缓冲 阻塞 IO 非阻塞 IO 无 选择器 1.1 面向流与面向缓

carl.zhao的专栏 532

Ubuntu 20.04 上 Geant4 安装避坑全记录:从源码编译到 B1 示例跑通(含数据包加速下载)

本文详细记录了在Ubuntu 20.04系统上从源码编译安装Geant4的全过程,包括环境准备、依赖安装、CMake参数解析、多线程编译优化以及数据包加速下载等关键步骤。特别针对B1示例的测试与验证提供了完整流程,帮助科研人员和学生避开常见安装陷阱,提升粒子物理模拟效率。

weixin_31220401的博客 313

18.Netty源码之ByteBuf 详解

highlight: arduino-light ByteBuf 是 Netty 的数据容器,所有网络通信中字节流的传输都是通过 ByteBuf 完成的。 然而 JDK NIO 包中已经提供了类似的 ByteBuffer 类,为什么 Netty 还要去重复造轮子呢?本节课我会详细地讲解 ByteBuf。 JDK NIO的ByteBuffer 我们首先介绍下 JDK NIO 的 Byte...

qq_30635523的博客 2193

详解岭回归与L2正则化

最小二乘法存在不可逆和病态问题,导致解析解不可计算或不稳定,岭回归是一种有效的解决方法,以损失无偏性来换取稳定解, 本文介绍详细介绍了岭回归的基本原理,并从L2正则化角度来进行了解释。

Luoyingfeng的博客 1万+

23、电生理与CSD分析:探索大脑活动的前沿技术

本文介绍了电生理与电流源密度(CSD)分析在探索大脑活动中的前沿应用。从电生理技术的发展现状,到局部场电位(LFPs)的起源与解释,重点阐述了CSD分析的原理、实验方法及其在绘制皮层兴奋流、解析突触输入和研究自发振荡中的广泛应用。文章还总结了该领域的优势与挑战,并展望了技术改进、多模态融合、数据分析创新及临床拓展的未来方向,展示了这些技术在揭示大脑功能机制中的关键作用。

Apple的专栏 122

Netty 网络编程深入学习【一】:ByteBuffer 源码解析

ByteBuffer是一个用于处理字节数据的缓冲区类。它是Java NIO 包的一部分,提供了一种高效的方式来处理原始字节数据。ByteBuffer可以用来读取、写入、修改和操作字节数据,它是一种直接操作字节的方式。

kkq的博客 925

模型预测控制(MPC)解析(六):有约束的MPC简介

本文为阅读笔记,仅供学习交流使用!!! 先从一个例子开始,说明当原始设计的控制信号满足操作约束时,控制系统的性能会显著恶化。并且只要稍加修改,如果在控制器的实现中加入约束,则性能恶化的程度可以降低,从而产生约束控制的思想。 在学习有约束控制之前,先看一个控制系统在控制信号饱和和不饱和的情况下运行的例子。 例:无阻尼振荡器的数学模型如下: 采样周期为Δt=0.1\Delta{t}=0.1Δt=0.1,对应的离散时间状态空间模型为: 设计目标是:设计一个预测控制系统,使得系统输出跟踪单位阶跃响应越快越好。预

行者无疆的博客 6655

Netty实战

在探究hbase的功能之前,为什么要设计出这样一套新的存储架构。 关系数据库系统的问题:hbase是一个分布式的,持久的、强一致性的存储系统,具有近似最优的写性能(能使用I/o利用率达到饱和)和出色的读性能,它充分利用了磁盘空间,支持特定列族切换可选压缩算法。 ...

wangjunji34478的专栏 437

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Netty 源码分析 08 buffer

Buffer 之 ByteBuf(一) Netty ByteBuf 相关的内容。它在buffer模块中实现,在功能定位上,它和 NIO ByteBuffer 是一致的,但是强大非常多

郭传志的博客 161

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Netty 系列笔记:NIO 核心组件 Buffer

一、概述 Buffer 的本质其实就是内存中的一块,类比常见的 ByteBuffer ,可以简单理解为 Byte 数组。Java NIO 将这块内存封装成 Buffer 对象,并提供一系列属性和方法,方便我们操作 Buffer 与 Channel 进行数据交互。 二、用法 我们以 FileChannel 操作来看: try (RandomAccessFile accessFile = new RandomAccessFile("/demo.txt", "rw");)

doubututou的博客 196

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

2.4 java面试题:Netty

Netty 是一个,用于快速开发高性能、高可靠性的网络 IO 程序。它在 Java 领域中的地位,就像“网络编程的 Spring”,几乎统治了所有需要自定义协议的中间件和分布式组件。老练的 Java 工程师说 Netty,不仅要讲“是什么”,还要讲清它,以及。

你是人间四月天 220

Netty5源码分析(五) -- ByteBuf缓冲区

Netty的ByteBuf缓冲区实现地比Java本身的ByteBuffer更加灵活,方便。它的类结构也比较复杂,这里只说ByteBuf核心的几个要点。 1. 最重要的是要理解为什么要ByteBuf这个组件。主要还是因为基于select / poll / epoll这种IO多路复用技术的NIO是非阻塞同步IO的模型,由于是同步IO,需要用户线程自己来处理IO的读写,由于是非阻塞的,每次调用

ITer_ZC的专栏 5749

Java IO模型BIO、NIO、AIO介绍

Java BlO就是传统的Java IO编程,其相关的类和接口在Java.io 包中BIO(blocking I/O)同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善(实现多个客户连接服务器).

liuhenghui5201的专栏 1488

05|Netty ByteBuf 源码分析:为什么不用 Java ByteBuffer

Netty ByteBuf 源码分析:高效数据缓冲设计 Netty 自研 ByteBuf 以解决 Java NIO ByteBuffer 在网络编程中的不足,主要针对高并发场景下的数据缓冲需求。ByteBuf 采用读写指针分离设计(readerIndex 和 writerIndex),消除了 ByteBuffer 需要 flip() 切换模式的繁琐操作,更符合网络协议解析的自然流程。 核心优势包括: 更直观的读写分离模型 支持动态扩容 提供堆内(Heap)和堆外(Direct)两种内存模式 通过池化技术(P

谢文峰的博客 341

[pravega-021] pravega源码分析--Controller子项目--关于netty[01]

0.nett 教程 《netty in action》2016年版本。和 《netty in action》浓缩版本https://github.com/waylau/essential-netty-in-action 1. netty的概念和家狗 1.1 单进程bio服务。从bio讲起,blocking io,同一时间,处理一个链接。 1.2 多线程bio服务。每个线程,从头到尾处理一...

大数据和机器学习研究 322

Netty 高性能的秘密:ByteBuf 与零拷贝机制

JDK 的 ByteBuffer 存在容量固定、API 繁琐的问题。Netty 的 ByteBuf 提供了动态扩容、读写指针分离、内存池化。零拷贝机制(Slice、CompositeBuffer、FileRegion)大幅减少内存复制开销。这是 Netty 性能远超 JDK NIO 的重要原因之一。👉 下一篇,我们将进入Netty 实战篇,看看它是如何在 RPC 框架、即时通讯、WebSocket 等场景中大显身手的。

波波烤鸭的博客 1099

Netty原理篇-ByteBuf

实际上,7种基本类型(boolean除外)都有自己的缓冲区实现,不过因为功能、方法、原理基本一致,所以仅讨论ByteBuffer。 Netty Api地址:http://netty.io/5.0/api/ 一 内容概述 NIO ByteBuffer的概述。 Netty ByteBuf的详细讲述,包括读、写、扩容、mark、reset、dupli...

weixin_34236869的博客 187

Netty-消息发送工作机制

业务调用write后,经过ChannelPipeline职责链处理,消息被投递到消息发送缓冲区待发送,调用flush之后会执行真正的发送操作,底层通过调用Java NIO的SocketChannel进行非阻塞write操作,将消息发送到网络上。    WriteAndFlushTask原理和源码分析    ChannelOutbou...

MarchRS的博客 1892

2024年Java最新NIO之缓冲区【基础内容】(1),阿里面试官跟我死磕MySQL

学完之后,若是想验收效果如何,其实最好的方法就是可自己去总结一下。比如我就会在学习完一个东西之后自己去手绘一份xmind文件的知识梳理大纲脑图,这样也可方便后续的复习,且都是自己的理解,相信随便瞟几眼就能迅速过完整个知识,脑补回来。下方即为我手绘的MyBtis知识脑图,由于是xmind文件,不好上传,所以小编将其以图片形式导出来传在此处,细节方面不是特别清晰。但可给感兴趣的朋友提供完整的MyBtis知识脑图原件(包括上方的面试解析xmind文档)

2401_84688466的博客 771

Netty源码解析 -- 零拷贝机制与ByteBuf

本文来分享Netty中的零拷贝机制以及内存缓冲区ByteBuf的实现。 源码分析基于Netty 4.1.52 Netty中的零拷贝 Netty中零拷贝机制主要有以下几种 1.文件传输类DefaultFileRegion#transferTo,调用FileChannel#transferTo,直接将文件缓冲区的数据发送到目标Channel,减少用户缓冲区的拷贝(通过linux的sendfile函数)。 使用read 和 write过程如下 使用sendfile 可以看到,使用sendfile函数可以减少数

binecy 433
上一篇: Netty源码分析---invokeHandlerAddedIfNeeded方法详解
下一篇: Netty源码分析---Netty-ByteBuf核心详解-简化版
不早睡不改名@
博客等级 码龄5年 536粉丝 306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值