【JAVA】普通IO数据拷贝次数的问题探讨

整个读取过程发生了两次数据拷贝,一次是DMA将磁盘上的文件数据拷贝到内核缓冲区,一次是将内核缓冲区的数据拷贝到用户缓冲区。在JAVA中,JVM划分了堆内存,平时创建的对象基本都在堆中,不过也可以通过NIO包下的ByteBuffer申请堆外内存:无论是普通IO或者是NIO,在进行文件读写的时候一般都会创建一个buffer作为数据的缓冲区,读写相关方法底层是通过调用native函数(JNI调用)来实现的,在进行读写时将buffer传递给JNI。
摘要由CSDN通过智能技术生成

最近看到网上有些文章在讨论JAVA中普通文件IO读/写的时候经过了几次数据拷贝,如果从系统调用开始分析,以读取文件为例,数据的读取过程如下(以缓存I/O为例):

  1. 应用程序调用read函数发起系统调用,此时由用户空间切换到内核空间;
  2. 内核通过DMA从磁盘拷贝数据到内核缓冲区;
  3. 将内核缓冲区的数据拷贝到用户空间的缓冲区,回到用户空间;

整个读取过程发生了两次数据拷贝,一次是DMA将磁盘上的文件数据拷贝到内核缓冲区,一次是将内核缓冲区的数据拷贝到用户缓冲区。

在JAVA中,JVM划分了堆内存,平时创建的对象基本都在堆中,不过也可以通过NIO包下的 ByteBuffer 申请堆外内存 DirectByteBuffer :

ByteBuffer.allocateDirect(size);

无论是普通IO或者是NIO,在进行文件读写的时候一般都会创建一个buffer作为数据的缓冲区,读写相关方法底层是通过调用native函数(JNI调用)来实现的,在进行读写时将buffer传递给JNI。

JNI一般使用C/C++代码实现,JNI底层调用C函数库时,要求buffer所在内存地址上的内容不能失效,但是JVM在进行垃圾回收的时候有可能对对象进行移动,导致地址发生变化,所以通过NIO进行文件读取的时候,从源码中可以明显看到对buffer的对象类型进行了判断,如果buffer是 DirectByteBuffer 类型,使用的是堆外内存,直接使用即可,反之则认为使用的是堆内内存,此时需要先申请一块堆外内存作为堆外内存buffer,然后进行系统调用,进行数据读取,读取完毕后将堆外内存buffer的内容再拷回JVM堆内内存buffer中,这里一般是没有疑问的。

比较有疑问的点是在普通IO中,读写文件传入的是字节数组 byte[] ,一种说法是数组一般分配的是连续的内存空间,即使内存地址发生了变化,根据数组的首地址依旧可以找到整个数组的内存,所以使用普通IO进行文件读写的时候,不需要重新分配堆外内存,直接使用堆内的字节数组即可,为了探究普通IO到底有没有重新申请堆外内存,接下来我们去看下源码。

普通IO

首先来看一下使用普通IO进行文件读取的例子,创建一个文件输入流和字节数组,通过输入流读取文件到字节数组中, 这里的字节数组占用的是JVM的堆内内存 :

// 创建输入流
    try (InputStream is = new FileInputStream("/document/123.txt")) {
        // 创建字节数组(堆内内存)
        byte[] bytes = new byte[1024];
        int len = 0;
        // 通过read方法读取数据到bytes数组
        while ((len = is.read(bytes)) != -1){
            String content = new String(bytes, 0, len);
            System.out.print(content);
        }
        is.read(bytes);
    } catch (Exception e) {
        e.printStackTrace();
    }

由于输入流使用的 FileInputStream ,所以读取文件会进入到 FileInputStream 中的 read 方法,可以看到里面又

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值