美文网首页
零拷贝简析及Java中的相关实现

零拷贝简析及Java中的相关实现

作者: 视频怪物 | 来源:发表于2019-12-22 16:04 被阅读0次

零拷贝, DMA(Direct Memory Access) copy, 即直接内存拷贝(不使用CPU拷贝), 是网络编程的关键,很多IO相关的性能优化都离不开。

传统数据copy方式

经过了4次拷贝和3次状态切换, 其中有2次DMA Copy

传统数据copy

步骤

  1. 从硬盘中读取数据, 使用DMA Copy拷贝到内核buffer中
  2. 再使用CPU Copy将数据从内核buffer中拷贝到用户buffer
  3. 再使用CPU Copy将数据从用户buffer拷贝到socket buffer
  4. 再使用DMA Copy将数据从socket buffer拷贝到协议栈中

mmap优化

经过了3次拷贝和3次状态切换, 其中有2次DMA copy

mmap优化

原理

memory map(内存映射), 通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户控件的拷贝次数。

步骤

  1. 从硬盘中读取数据, 使用DMA Copy拷贝到内核buffer中
  2. 使用mmap将文件映射到内核buffer中和用户buffer共享, 无需再次拷贝到用户buffer中
  3. 再使用CPU Copy将数据从用户buffer拷贝到socket buffer
  4. 再使用DMA Copy将数据从socket buffer拷贝到协议栈中

sendFile优化

Linux 2.4 -

经过了3次拷贝和2次状态切换, 其中有2次DMA copy

Linux 2.4- 版本 sendFile
原理

Linux在2.4版本之前提供的 sendFile 函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer,同时,由于和用户态完全无关,就减少了一次上下文切换。

步骤
  1. 从硬盘中读取数据, 使用DMA Copy拷贝到内核buffer中
  2. 再使用CPU Copy将数据从内核buffer直接拷贝到socket buffer
  3. 再使用DMA Copy将数据从socket buffer拷贝到协议栈中

Linux 2.4 +

经过了2次拷贝, 其中近似没有CPU copy (可以看作完全实现了零拷贝)

Linux 2.4+ 版本

原理

相对于之前Linux版本中的sendFile做了一些修改,极大地避免了从内核缓冲区CPU Copy到 Socket buffer 的操作(这里其实会有一次cpu拷贝,但是拷贝的信息很少, 主要是一些描述信息, 比如lenght , offset, 这些信息会从kernel buffer拷贝到socket buffer, 但是过程中的消耗非常低,可以忽略),直接拷贝到协议栈,从而再一次减少了数据拷贝。

Java Nio 零拷贝

使用transferTo()/transferFrom()函数

原理

/*
 * <p> This method is potentially much more efficient than a simple loop
 * that reads from the source channel and writes to this channel.  Many
 * operating systems can transfer bytes directly from the source channel
 * into the filesystem cache without actually copying them.  </p>
 * 
 */ 
public abstract long transferFrom(ReadableByteChannel src, long position, long count) throws IOException;

许多操作系统可以直接将字节从源通道转移到文件系统缓存中,而无需实际复制它们, 而transferTo()/transferFrom()函数底层使用MappedByteBuffer来实现, 可以让文件直接在内存(堆外内存)中进行修改, 操作系统不需要再拷贝一次, MappedByteBuffer操作内存相关代码请点击查看

代码

public static void transferFrom() {
    File sourceFile = new File("./source.log");
    File targetFile = new File("./target1.log");
    try (
            FileInputStream fileInputStream = new FileInputStream(sourceFile);
            FileChannel fileInputStreamChannel = fileInputStream.getChannel();
            FileOutputStream fileOutputStream = new FileOutputStream(targetFile);
            FileChannel fileOutputStreamChannel = fileOutputStream.getChannel();
    ) {
        fileOutputStreamChannel.transferFrom(fileInputStreamChannel, 0, fileInputStreamChannel.size());
    } catch (Exception e) {
        e.printStackTrace();
    }
}

相关文章

  • 零拷贝简析及Java中的相关实现

    零拷贝, DMA(Direct Memory Access) copy, 即直接内存拷贝(不使用CPU拷贝), 是...

  • 2019-10-29 零拷贝

    参见:Java中的零拷贝 先提出两个问题: IO过程中,哪些步骤进行了拷贝?哪些地方零拷贝? Java支持哪些零拷...

  • 零拷贝的原理及Java实现

    在谈论Kafka高性能时不得不提到零拷贝。Kafka通过采用零拷贝大大提供了应用性能,减少了内核和用户模式之间的上...

  • java基础_反射

    相关文章 : 1. 公共技术点之 Java 反射 Reflection;2. Java反射原理简析;3. java...

  • 简析Java的浅拷贝和深拷贝

    浅拷贝:使用一个已知实例对新创建实例的成员变量逐个赋值。深拷贝:当一个类的拷贝构造方法,不仅要复制对象的所有非引用...

  • Java中的零拷贝原理

    [TOC] 先提出两个问题:IO过程中,哪些步骤进行了拷贝?哪些地方零拷贝?Java支持哪些零拷贝? 哪里听说过零...

  • Java中的零拷贝

    先提出两个问题:IO过程中,哪些步骤进行了拷贝?哪些地方零拷贝?Java支持哪些零拷贝? 带着这俩问题,我们一起来...

  • C++ 拷贝控制(二) — 移动构造函数和移动赋值运算符

    相关文章: C++ 拷贝控制(一) — 析构函数、拷贝构造函数与拷贝赋值函数 C++ 引用类型 — 左值引用、常引...

  • JAVA IO专题一:java InputStream和Outp

    笔者相关文章 java NIO读取文件并通过socket发送,最少拷贝了几次?堆外内存和所谓的零拷贝到底是什么关系...

  • GeekBand class2

    1.在具有指针的类中,必须具有拷贝函数、拷贝赋值函数、析构函数这三种内容,其实现形式如下: #ifndef _MY...

网友评论

      本文标题:零拷贝简析及Java中的相关实现

      本文链接:https://www.haomeiwen.com/subject/dxponctx.html