IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Java中的零拷贝 -> 正文阅读

[Java知识库]Java中的零拷贝

前言:

在Java程序中,零拷贝技术分为两种:mmap(内存映射)和sendFile,首先要了解零拷贝的概念:所谓的零拷贝不是不拷贝,而是不经过CPU拷贝,它还是需要拷贝的(比如将数据从硬盘拷贝到内核态),这个零拷贝是从操作系统(CPU)的角度看的

在这里插入图片描述

传统的IO拷贝

首先将硬盘上的数据拷贝到内核,然后在经过CPU拷贝将数据从内核拷贝到应用程序内存(用户态),在应用程序内存,用户可以对数据进行操作修改等,然后在经过CPU拷贝将数据从用户缓冲区拷贝到socket缓冲区,然后在经过DMA拷贝,将数据从socket缓冲区拷贝到网卡。
那么经过以上的步骤,完成了将数据从本地硬盘传输到网络上的过程,
那这个过程数据的拷贝经过了:
硬盘—>内核—>应用程序内存(可以理解为用户态,相当于jvm中)—>socket缓冲区—>网卡,这4次拷贝的过程。
上下文的切换经过了:用户态–>内核态–>用户态 这三次上下文切换
在这里插入图片描述

mmap:

首先将硬盘上面的数据数据拷贝到内核,(因为mmap技术,做到了内核态数据和用户态数据共享,此时不需要将数据从内核拷贝到用户态,用户态也可以对数据进行修改),再将内核态的数据经过CPU拷贝,拷贝到socket缓冲区,在经过DMA拷贝,将socket缓冲区的数据拷贝到协议栈;
那经过了mmap的优化后,数据的读写少了一次拷贝的过程,但是mmap还不是真正意思上的零拷贝,因为它还是进行了拷贝
那这个过程数据的拷贝经过了:
硬盘—>内核—>socket缓冲区—>网卡,这3次拷贝的过程。
上下文的切换经过了:用户态–>内核态–>用户态 这三次上下文切换

在这里插入图片描述

sendFile

sendFile是Linux2.1版本提供的函数,基本的原理就是数据根本不经过用户态,直接从内核缓冲区进入到SocketBuffer,同时,由于和用户态完全无关,就减少了一次上下文切换;
过程:
首先将硬盘上面的数据经过DMA拷贝(直接内存拷贝),将数据拷贝到内核,再将内核态的数据经过CPU拷贝,拷贝到socket缓冲区,再由DMA拷贝将数据从socket缓冲区拷贝到协议栈。
目前来看sendFile和mmap拷贝是差不多的,但是sendFile比mmap拷贝少了一次上下文的切换,
但是就目前看来,这两种拷贝都没有达到真正的零拷贝。

在这里插入图片描述

sendFile(增强)

在Linux2.4的版本中,对sendFile做了一些修改,真正实现了零拷贝;
过程:
首先将硬盘上面的数据拷贝到内核,此时在经过CPU拷贝将数据的描述信息拷贝到socket缓冲区(注意:此时拷贝的是数据的描述信息,数据量很小,所以此次拷贝可以忽略不记),然后此时数据其实还是在内核的(因为刚刚的CPU拷贝只是拷贝了一些数据描述),再将数据从内核直接拷贝到网卡。
在这个版本中,sendFile就实现了真正的零拷贝,虽然还是经过了一次CPU的拷贝,但是数据量很小,所以可以忽略不记。

Java+NIO实现零拷贝

在java中可以使用:
fileChannel.transferTo()
和 fileChannel.map() 等函数来实现零拷贝

其中:
mmap适合小数据量的传输, RocketMQ使用的就是mmap。
sendFile 适合大数据量的传输,Kafka使用的就是sendFile。

Java 实现 mmap示例

  package org.xhs.json;

import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @Author: hu.chen
 * @Description:
 * @DateTime: 2022/4/29 1:29 AM
 **/
public class MmpTest {


    public static void main(String[] args) {
        try {
            // 获取文件
            FileChannel readChannel = FileChannel.open(Paths.get("C://test/jay.txt"), StandardOpenOption.READ);
            MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);
            FileChannel writeChannel = FileChannel.open(Paths.get("E://test1/siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
            //数据传输
            writeChannel.write(data);
            readChannel.close();
            writeChannel.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

Java实现sendFile示例:

示例1:

package org.xhs.json;

import java.nio.channels.FileChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 * @Author: hu.chen
 * @Description:
 * @DateTime: 2022/5/11 12:45 PM
 **/
public class SendfileTest {

    public static void main(String[] args) {
        try {
            FileChannel readChannel = FileChannel.open(Paths.get("C://test/jay.txt"), StandardOpenOption.READ);
            long len = readChannel.size();
            long position = readChannel.position();
            FileChannel writeChannel = FileChannel.open(Paths.get("E://test1/siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
            //数据传输
            //开始发送数据:在Java中使用零拷贝技术调用transferTo方法,这个方法底层使用了零拷贝技术
            // 在Linux系统下 使用transferTo 方法,没有文件大小限制,可以将文件调用一次transferTo方法即可传输完成
            //但是在Windows系统下调用一次transferTo 方法,最多只能发送 8m 的数据,所以需要将文件进行分段传输
            // transferTo 参数介绍:
            //              第一个参数:从文件的哪里开始读取
            //              第二个参数:读取多少字节
            //              第三个参数:将读取的字节,放入需要写入的Channel中
            readChannel.transferTo(position, len, writeChannel);
            readChannel.close();
            writeChannel.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

    }
}

示例2:

  public void writeHtml(File file) {
        if (file.exists() && file.isFile()) {
            try {
                System.err.println("文件存在");

                //文件存在进行输出,此处使用零拷贝技术

                //获取到该 channel 关联的 缓存Buffer
                ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

                //得到一个文件 通道
                FileChannel fileChannel = new FileInputStream(file).getChannel();
                writeBuffer.put(HttpProtocolUtil.sendHead(fileChannel.size(),"200"));
                writeBuffer.flip();
                channel.write(writeBuffer);

                //开始发送数据:在Java中使用零拷贝技术调用transferTo方法,这个方法底层使用了零拷贝技术
                // 在Linux系统下 使用transferTo 方法,没有文件大小限制,可以将文件调用一次transferTo方法即可传输完成
                //但是在Windows系统下调用一次transferTo 方法,最多只能发送 8m 的数据,所以需要将文件进行分段传输
                // transferTo 参数介绍:
                //              第一个参数:从文件的哪里开始读取
                //              第二个参数:读取多少字节
                //              第三个参数:将读取的字节需要放入的SocketChannel
                long count = fileChannel.transferTo(0, fileChannel.size(), channel);

                System.err.println("传输的总的字节大小:"+count);
                //关闭通道
                close();
            } catch (Exception e) {
                e.printStackTrace();
                System.err.println("写出静态资源失败");
            }
        } else {
            doWrite(HttpProtocolUtil.send404("404 资源未找到"));
            //关闭通道
            close();
        }
    }
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-13 11:38:35  更:2022-05-13 11:39:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 21:22:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码