第五天:深度解密 Netty ByteBuf:高性能 IO 的基石

Netty ByteBuf:直接内存 vs 堆内存

Netty的ByteBuf分配和Java NIOByteBuffer类似

复制代码
// 堆内存
ByteBuf heapBuf = allocator.heapBuffer(10);

// 直接内存
ByteBuf directBuf = allocator.directBuffer(10);

|---------|-------------|----------------|
| 对比项 | 堆内存 ByteBuf | 直接内存 ByteBuf |
| 内存位置 | JVM 堆 | JVM 堆外 |
| GC 管理 | 是 | 否 |
| IO 性能 | 慢(多一次拷贝) | 快(少一次拷贝) |
| 创建成本 | 低 | 高 |
| 是否需手动释放 | 否 | 是(release) |

Direct ByteBuf 提高 IO 性能、降低 GC 压力,但创建成本高且需要手动释放;Heap ByteBuf 管理简单,但 IO 性能差。

按你刚才的要求,继续**极限精简,只保留"有用信息"**👇


Netty ByteBuf:池化 vs 非池化(精简版)

复用 ByteBuf,避免频繁创建 / 销毁的事件耗费

2️⃣ 核心差异

|------------|-------------------|--------|
| 对比 | 非池化 | 池化 |
| ByteBuf 获取 | 每次 new | 从池中复用 |
| 直接内存成本 | 高(频繁 malloc/free) | 低 |
| GC / 内存压力 | 大 | 小 |
| 并发场景 | 不友好 | 友好 |


3️⃣ 启用方式

复制代码
-Dio.netty.allocator.type=pooled   # 池化
-Dio.netty.allocator.type=unpooled # 非池化

4️⃣ 默认策略(记结论)

  • Netty 4.1+ :非 Android 默认 池化
  • Android:默认非池化
  • 4.1 之前:默认非池化(池化不成熟)

池化通过复用 ByteBuf 降低直接内存分配成本和 GC 压力,是 Netty 在高并发 IO 场景下的关键优化手段。

组成

ByteBuf由四部分组成

  1. 读指针(readerIndex):标记当前可读数据的起始位置。
  2. 写指针(writerIndex):标记当前可写数据的起始位置。
  3. 容量(capacity):当前 ByteBuf 实际占用的内存大小。
  4. 最大容量(maxCapacity):ByteBuf 可扩容到的最大内存限制。

相比于ByttBuffer,不用来回切换读写模式更方便,且支持动态扩容

整数大端写入端:更符合读书习惯

整数小端写入: CPU 从低位到高位的运算顺序,内存访问更连续。

ByteBuf扩容规则:

  1. 如果写入字节小于512,则容量下一次为16的整数倍。
  2. 如果写入字节大于512,则容量下一次为2^n
  3. 扩容后不能超过max capacity

内存释放

核心机制:引用计数 (Reference Counting)

Netty 的 ByteBuf 实现了 ReferenceCounted 接口。

  • 初始状态: 创建一个新的 ByteBuf 时,引用计数 refCnt1
  • Retain (保留): 调用 buf.retain(),引用计数 +1。表示有新的地方在使用它。
  • Release (释放): 调用 buf.release(),引用计数 -1
  • 回收: 当引用计数变为 0 时,Netty 会将该内存块归还给内存池(Pooled)或直接销毁(Unpooled)。

警告: 如果引用计数未归零,GC 无法回收堆外内存(Direct Memory),将直接导致 内存泄漏 (Memory Leak) 。如果引用计数归零后继续访问即使ByteBuf对象还在,但是底层内存会被回收,会抛出 IllegalReferenceCountException

释放时机:而在netty中一个基本原则:"谁最后使用(消费)了数据,谁就负责释放。"

Slice;切片

【零拷贝】的体现之一,对原始 ByteBuf 进行切片成多个 ByteBuf, 切片后的 ByteBuf 并没有发生内存复制,还是使用原始 ByteBuf 的内存,切片后的 ByteBuf 维护独立的 read, write 指针

逻辑上对ByteBuf进行切分,其实物理内存还是同一块

ByteBuf.slice(index1,index2)

index1:起始位置

index2:切片长度

切片共享原始内存,容量固定,原 ByteBuf 一旦释放,切片就不可用了;

写入超界会抛异常,安全使用需要正确管理引用计数。

duplicate

【零拷贝】的体现之一,就好比截取了原始 ByteBuf 所有内容,并且没有 max capacity 的限制,也是与原始ByteBuf 使用同一块底层内存,只是读写指针是独立的

零拷贝相反Copy

会将底层内存数据进行深拷贝,无论读写,都与原始ByteBuf无关

Composite

CompositeByteBuf

把多个 ByteBuf 逻辑上拼接成一个连续缓冲区

unPooled

unpooled 是 Netty 提供的一个 工具类,用来创建 非池化(unpooled)的 ByteBuf,区别于 Netty 的 池化 ByteBuf(PooledByteBuf)。它的核心作用和特点可以总结如下:

相关推荐
蚰蜒螟9 分钟前
一次 Spring AOP 与定时任务引发的死锁排查实录
java·spring·firefox
TeamDev9 分钟前
JxBrowser 9.3.1 版本发布啦!
java·前端·javascript·c#·混合应用·jxbrowser·浏览器控件
程序猿乐锅43 分钟前
【数据结构与算法 | 第六篇】力扣1109,1094差分数组
java·算法·leetcode
yeflx1 小时前
速腾Airy雷达使用记录
java·服务器·网络
乐之者v1 小时前
AI编程 -- Agents.md 的简单示例
java·ai编程
无风听海2 小时前
Claude Agent Skills 的四种设计模式;从渐进式披露到最小权限
java·算法·设计模式
geovindu2 小时前
java: Facade Pattern
java·开发语言·后端·外观模式·结构型模式
listening7772 小时前
HarmonyOS 6.1 元服务深度优化:从“秒开”到“常驻”的极致体验
java·开发语言·spring
AC赳赳老秦2 小时前
司法公开数据采集应用:OpenClaw 抓取裁判文书公开信息,批量整理同类参考案例
java·大数据·python·数据挖掘·数据分析·php·openclaw
笑小枫3 小时前
用 Claude Code 推翻重写笑小枫网站
java·人工智能·spring boot·ai编程