第五天:深度解密 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)。它的核心作用和特点可以总结如下:

相关推荐
xiaobaishuoAI4 小时前
后端工程化实战指南:从规范到自动化,打造高效协作体系
java·大数据·运维·人工智能·maven·devops·geo
期待のcode4 小时前
TransactionManager
java·开发语言·spring boot
Hello.Reader4 小时前
PyFlink JAR、Python 包、requirements、虚拟环境、模型文件,远程集群怎么一次搞定?
java·python·jar
计算机学姐4 小时前
基于SpringBoot的汽车租赁系统【个性化推荐算法+数据可视化统计】
java·vue.js·spring boot·后端·spring·汽车·推荐算法
七夜zippoe4 小时前
分布式事务解决方案 2PC 3PC与JTA深度解析
java·分布式事务·cap·2pc·3pc·jta
我是人✓4 小时前
Spring IOC入门
java·数据库·spring
好好研究4 小时前
SpringBoot小案例打包执行流程
java·spring boot·后端
Albert Edison4 小时前
【Git】多人协作一(同一分支下)
git·vscode·svn·github
rgeshfgreh4 小时前
Spring Bean管理机制深度解析
java·spring boot·spring