直接缓冲区
为什么要用直接缓冲区?
因为,操作系统
进行 I/O 操作的目标内存区域
必须是连续的字节序列
。(因此只有字节缓冲区
有资格参与 I/O 操作)
但是,在 JVM 中,字节数组元素可能不会在堆中连续存储,或者 GC 可能随时对其进行移动。出于这一原因,引入了直接缓冲区
的概念。
非直接字节缓冲区
可能导致性能损耗。通常非直接缓冲不可能成为一个本地 I/O 操作的目标。如果您向一个通道中传递一个非直接 ByteBuffer 对象用于写入
,通道可能会在每次调用中隐含
地进行下面的操作:
- 创建一个
临时
的直接
ByteBuffer 对象。 - 将
非直接
缓冲区的内容复制
到临时直接
缓冲区。 - 使用临时直接缓冲区执行低层次 I/O 操作。
- 临时直接缓冲区对象离开作用域,并最终成为被回收的无用数据。
也就是说底层会用直接缓冲区中转
。这可能导致缓冲区在每个 I/O 上复制
并产生大量对象,而这种事都是我们极力避免的。
当然,依靠工具,事情可以不这么糟糕。运行时可能会缓存并重新使用直接缓冲区或者执行其他一些聪明的技巧来提高吞吐量。如果您仅仅为一次使用而创建了一个缓冲区,区别并不是很明显。另一方面,如果您将在一段高性能脚本中重复使用缓冲区,分配直接缓冲区并重新使用它们会使您游刃有余。
直接缓冲区时 I/O 的最佳选择,但可能比创建非直接缓冲区要花费更高的成本。直接缓冲区使用的内存是通过系统调用
分配的,绕过了标准 JVM 堆栈。系统调用很影响性能
,所以,建立和销毁直接缓冲区会明显比具有堆栈的缓冲区更加破费,这取决于主操作系统以及 JVM 实现。 直接缓冲区的内存区域不受 GC 控制,因为它们位于标准 JVM 堆栈之外。
网友评论