如何区分 NIO 中的 DirectBuffer 与 HeapBuffer 在磁盘 IO 与网络传输时的性能差异?

浅萱小哥_1938

浅萱小哥_1938

2026-05-02

734人浏览

原创

DirectBuffer 在 IO 通道写入时更快,因其支持零拷贝:JVM 直接将物理内存地址传给内核;而 HeapBuffer 需先复制到临时 DirectBuffer,小数据时开销显著。

如何区分 nio 中的 directbuffer 与 heapbuffer 在磁盘 io 与网络传输时的性能差异?

DirectBuffer 在网络传输和磁盘 IO 中性能更好,但仅当缓冲区被反复复用、且单次传输数据量较大时才明显;HeapBuffer 在小数据、短生命周期场景下更轻量、更安全。

为什么 DirectBuffer 在 IO 通道写入时更快?

关键在于零拷贝路径:当调用 channel.write(directBuffer) 时,JVM 可直接将 address 指向的物理内存地址传给内核,数据从用户态直接送入 socket 或文件的内核缓冲区;而 channel.write(heapBuffer) 必须先触发一次 JVM 内部的隐式复制——底层会临时分配一个 DirectByteBuffer,再把 heapBuffer.array() 的内容 System.arraycopy 过去,之后才走相同路径。

  • 这个复制过程对小 buffer(如 allocate(64))开销占比极高,甚至可能慢 2–3 倍
  • Netty 等框架默认读取用 allocateDirect,就是为避免每次 read 都触发该复制
  • 注意:如果后续还要对 buffer 做频繁数组访问(如解析协议头),heapBuffer.array() 是直接引用,directBuffer.array() 会抛 UnsupportedOperationException

HeapBuffer 在什么磁盘 IO 场景下反而更合适?

当 buffer 生命周期极短、且不直接参与 FileChannel 传输时,例如:内存中拼装 JSON 后一次性写入文件、日志格式化后暂存再刷盘。这类操作本质是「CPU 密集型」而非「IO 密集型」。

  • ByteBuffer.allocate(4096) 分配快,GC 可控,无 MaxDirectMemorySize 越界风险
  • 若用 allocateDirect(4096) 做这种临时缓存,反而因 JNI 分配慢 + 无法及时释放(依赖 GC 触发 Cleaner)导致堆外内存缓慢泄漏
  • Files.write(path, bytes) 这类高层 API 内部已优化,不会从你传入的 byte[] 构造 HeapByteBuffer 再转 DirectBuffer,它走的是 native writev 路径,与 buffer 类型无关

如何快速判断当前 buffer 是 Direct 还是 Heap?

别依赖 instanceof 或类名字符串匹配,用标准 API:

  • buffer.isDirect() —— 返回 true 即为 DirectByteBuffer
  • buffer.hasArray() —— 对 HeapByteBuffer 返回 true,DirectByteBuffer 返回 false
  • 错误写法:buffer.getClass().getName().contains("Direct"),在某些 JDK 版本或自定义实现中不可靠

特别注意:通过 ByteBuffer.wrap(byte[]) 创建的一定是 HeapByteBuffer,哪怕原数组来自 Unsafe.allocateMemory;而 allocateDirect 创建的对象,其 array() 方法永远抛异常。

容易被忽略的资源泄漏点

DirectBuffer 的「间接性」常被低估:它的 Java 对象(DirectByteBuffer 实例)在堆上,受 GC 管理;但真正的内存块在堆外,只有当该对象被 GC 回收、且 Cleaner 执行后才会释放。这意味着:

  • 如果 buffer 被长期强引用(比如放进静态 ConcurrentHashMap),堆外内存永不释放,OutOfMemoryError: Direct buffer memory 会先于堆溢出发生
  • Buffer.clear() 或 rewind() 不释放内存,只是重置指针
  • JDK 9+ 可用 Buffer.clear() 后手动调用 cleaner.clean()(需反射获取),但生产环境不推荐——应优先设计复用池,而非手动清理

真正需要警惕的不是「怎么选」,而是「选了之后怎么活过一周」:DirectBuffer 的生命周期必须比使用它的 Channel 更长,且不能脱离作用域意外逃逸。

数码产品性能查询
数码产品性能查询

该软件包括了市面上所有手机CPU,手机跑分情况,电脑CPU,电脑产品信息等等,方便需要大家查阅数码产品最新情况,了解产品特性,能够进行对比选择最具性价比的商品。

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

2023.06.15

11457

6

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

2023.07.05

8562

9

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

2023.07.31

7372

8

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.01

1224

3

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.08.02

988

3

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

1476

5

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.02

3009

5

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

2023.08.03

20271

3

配置java环境变量
配置java环境变量

配置Java环境变量是为了让操作系统能够识别和使用Java的相关命令和功能。本专题为大家提供配置java环境变量相关文章,帮助大家解决问题。

2023.08.03

1315

8

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.1万人学习