直接与非直接缓冲区

  字节缓冲区跟其他缓冲区类型最明显的不同在于,它们可以成为通道所执行的 I/O 的源头和/或目标。其实发现通道只接收ByteBuffer作为参数这个将Channel的时候会发现。

类型优点缺点
直接缓冲区在虚拟机内存外,开辟的内存,
IO操作直接进行,没有再次复制
创建和销毁开销大
非直接缓冲区在虚拟机内存中创建,易回收但占用虚拟机内存开销,
处理中有复制过程。

直接缓冲区

  直接缓存区是在虚拟机内存外,开辟的内存,IO操作直接进行,不再对其进行复制,但创建和销毁开销大。

在这里插入图片描述

非直接缓冲区

  非直接缓存区在虚拟机内存中创建,易回收,但占用虚拟机内存开销,处理中有复制过程。

在这里插入图片描述

直接和非直接缓冲区解释

  操作系统在内存区域中进行I/O操作,这些内存区域,就操作系统方面而言,是相连的字节序列。所以,只有字节缓冲区有资格参与I/O操作。操作系统会直接存取进程——在本例中是JVM进程的内存空间,以传输数据。这也意味着I/O操作的目标内存区域必须是连续的字节序列。在JVM中,字节数组可能不会在内存中连续存储,或者无用存储单元收集可能随时对其进行移动。在Java中,数组是对象,而数据存储在对象中的方式在不同的JVM实现中都各有不同。出于这一原因,引入了直接缓冲区的概念。

  直接字节缓冲区通常是I/O操作最好的选择。在设计方面,它们支持JVM可用的最高效I/O机制。非直接字节缓冲区可以被传递给通道,但是这样可能导致性能损耗。通常非直接缓冲不可能成为一个本地I/O操作的目标。如果向一个通道中传递一个非直接ByteBuffer对象用于写入,通道可能会在每次调用中隐含地进行下面的操作:

  1. 创建一个临时的直接ByteBuffer对象。
  2. 将非直接缓冲区的内容复制到临时缓冲中。
  3. 使用临时缓冲区执行低层次I/O操作。
  4. 临时缓冲区对象离开作用域,并最终成为被回收的无用数据。

  直接缓冲区是I/O的最佳选择,但可能比创建非直接缓冲区要花费更高的成本。直接缓冲区使用的内存是通过调用本地操作系统方面的代码分配的,绕过了标准JVM堆栈。建立和销毁直接缓冲区会明显比具有堆栈的缓冲区更加破费,这取决于主操作系统以及JVM实现。直接缓冲区的内存区域不受无用存储单元收集支配,因为它们位于标准JVM堆栈之外。

  直接ByteBuffer是通过调用ByteBuffer.allocateDirect()函数产生的,注意用一个wrap()函数所创建的被包装的缓冲区总是非直接的。

public abstract class ByteBuffer extends Buffer implements Comparable {
    // This is a partial API listing
    public static ByteBuffer allocate(int capacity)
    public static ByteBuffer allocateDirect(int capacity)
    public abstract boolean isDirect();
}

使用直接缓冲区有两种方式:

  1. 缓冲区创建的时候分配的是直接缓冲区
  2. 在FileChannel上调用map()方法,将文件直接映射到内存中创建
Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐