Java中三种零拷贝的实现示例以及对比详解

 更新时间:2023年12月21日 10:49:01   作者:Colins~  
这篇文章主要介绍了Java中三种零拷贝的实现示例以及对比详解,本文主要是介绍几种零拷贝的实现示例,以及与最传统的做一个对比,看看在效率上到底有多大的提升,需要的朋友可以参考下

简介

本文主要是介绍几种零拷贝的实现示例,以及与最传统的做一个对比,看看在效率上到底有多大的提升

好了,废话不多说直接干,本章例子是通过网络IO传输一个8M大小的文件,对比传输效率,由于服务端接收端不需要修改,所以我们先上服务端代码:

public static void main(String[] args) throws IOException {
    ServerSocket serverSocket = new ServerSocket(8080);
    System.out.println("服务端:等待连接");
    Socket accept = serverSocket.accept();
    System.out.println("服务端:" + accept.getRemoteSocketAddress() + "已连接");
    File file = new File("C:\\Users\\Administrator\\Desktop\\ioTest.txt");
    if(!file.exists()){
        file.createNewFile();
    }
    FileOutputStream fileOutputStream = new FileOutputStream(file);
    InputStream bufferedInputStream = accept.getInputStream();
    byte[] bytes = new byte[2048];
    int read;
    while ((read = bufferedInputStream.read(bytes,0,2048)) != -1) {
        fileOutputStream.write(bytes);
    }
    OutputStream outputStream = accept.getOutputStream();
    outputStream.write("接收完毕".getBytes());
    accept.shutdownOutput();
    fileOutputStream.close();
    outputStream.close();
    bufferedInputStream.close();
    accept.close();
}

传统实现

正常的socket传输,耗时:46ms

public static void normal() throws IOException {
        Socket socket = new Socket("127.0.0.1", 8080);
        OutputStream outputStream = socket.getOutputStream();
        InputStream inputStream = socket.getInputStream();
        long start = System.currentTimeMillis();
        File file = new File("C:\\Users\\Administrator\\Desktop\\222.txt");
        FileInputStream fileInputStream = new FileInputStream(file);
        byte[] bytes1 = new byte[2048];
        while (fileInputStream.read(bytes1, 0, 2048) != -1) {
            outputStream.write(bytes1);
        }
        socket.shutdownOutput();
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        byte[] bytes = new byte[1024];
        String message = "";
        int read;
        while ((read = inputStream.read(bytes)) != -1) {
            message += new String(bytes, 0, read);
        }
        System.out.println("服务端发来消息->" + message);
        inputStream.close();
        outputStream.close();
        socket.close();
    }

MMAP

MMAP原理就是建立了一个文件映射,划分了一个虚拟空间,往这个空间写数据,少了一次拷贝

缺点:空间有限

实践案例:RocketMq

耗时:32ms

public static void mmp() throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
        long start = System.currentTimeMillis();
        Path path = Paths.get("C:\\Users\\Administrator\\Desktop\\222.txt");
        FileChannel open = FileChannel.open(path, StandardOpenOption.READ);
        MappedByteBuffer map = open.map(FileChannel.MapMode.READ_ONLY, 0, open.size());
        socketChannel.write(map);
        socketChannel.shutdownOutput();
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        int read = socketChannel.read(allocate);
        if (read > 0) {
            allocate.flip();
            byte[] bytes = new byte[allocate.remaining()];
            allocate.get(bytes);
            System.out.println("服务端发来消息:" + new String(bytes));
        }
        socketChannel.close();
    }

transferTo

原理就是两个通道之间直接传输数据,根据系统支持程度,少了1-2次拷贝

缺点:局限于文件通道

实践案例:Netty、Kafka

耗时:18ms

 public static void transferTo() throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
        long start = System.currentTimeMillis();
        Path path = Paths.get("C:\\Users\\Administrator\\Desktop\\222.txt");
        FileChannel open = FileChannel.open(path, StandardOpenOption.READ);
        long l = open.transferTo(0, open.size(), socketChannel);
        socketChannel.shutdownOutput();
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        int read = socketChannel.read(allocate);
        if (read > 0) {
            allocate.flip();
            byte[] bytes = new byte[allocate.remaining()];
            allocate.get(bytes);
            System.out.println("服务端发来消息:" + new String(bytes));
        }
        socketChannel.close();
    }

堆外内存

原理直接使用堆外内存,少了一次拷贝

缺点:堆外内存开启耗时,此内存不受JVM控制,如垃圾回收等

实践案例:Netty

耗时:26ms

public static void outSide() throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
        long start = System.currentTimeMillis();
        Path path = Paths.get("C:\\Users\\Administrator\\Desktop\\222.txt");
        FileChannel open = FileChannel.open(path, StandardOpenOption.READ);
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect((int) open.size());
        open.read(byteBuffer);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
        socketChannel.shutdownOutput();
        System.out.println("耗时:" + (System.currentTimeMillis() - start));
        ByteBuffer allocate = ByteBuffer.allocate(1024);
        int read = socketChannel.read(allocate);
        if (read > 0) {
            allocate.flip();
            byte[] bytes = new byte[allocate.remaining()];
            allocate.get(bytes);
            System.out.println("服务端发来消息:" + new String(bytes));
        }
        socketChannel.close();
    }

总结

耗时统计不完全准确,都是多次取平均,具体使用哪种需要看场景来

到此这篇关于Java中三种零拷贝的实现示例以及对比详解的文章就介绍到这了,更多相关Java零拷贝方式对比内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MyBatis中动态SQL的使用指南

    MyBatis中动态SQL的使用指南

    MyBatis 是一个流行的持久层框架,它通过 XML 或注解将接口方法与 SQL 映射在一起,动态 SQL 是 MyBatis 的一大特性,它使得构建灵活的查询变得简单,本文将通过一个 User 表的示例,介绍 MyBatis 中常用的动态 SQL 方法,需要的朋友可以参考下
    2024-09-09
  • Spring boot + mybatis + orcale实现步骤实例代码讲解

    Spring boot + mybatis + orcale实现步骤实例代码讲解

    这篇文章主要介绍了Spring boot + mybatis + orcale的实现步骤实例代码讲解,需要的朋友可以参考下
    2017-12-12
  • 使用Java实现2048小游戏代码实例

    使用Java实现2048小游戏代码实例

    这篇文章主要介绍了使用Java实现2048小游戏代码实例,2048 游戏是一款益智类游戏,玩家需要通过合并相同数字的方块,不断合成更大的数字,最终达到2048,游戏规则简单,但挑战性很高,需要玩家灵活运用策略和计算能力,本文将使用Java代码实现,需要的朋友可以参考下
    2023-10-10
  • java 压缩和解压缩Zip、Jar、Gzip文件实例代码

    java 压缩和解压缩Zip、Jar、Gzip文件实例代码

    本文主要介绍java压缩和解压缩Zip、Jar、Gzip文件的知识,这里整理了相关资料,并附示例代码有兴趣的小伙伴可以参考下
    2016-09-09
  • Java使用PDFBox实现操作PDF文档

    Java使用PDFBox实现操作PDF文档

    这篇文章主要为大家详细介绍了Java如何使用PDFBox实现操作PDF文档,例如添加本地图片、添加网络图片、图片宽高自适应、图片水平垂直居中对齐等功能,需要的可以了解下
    2024-03-03
  • 通俗讲解JVM的类加载机制

    通俗讲解JVM的类加载机制

    这篇文章主要介绍了JVM的类加载机制的相关资料,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-09-09
  • Kafka Producer中的消息缓存模型图解详解

    Kafka Producer中的消息缓存模型图解详解

    Kafka中消息是以Topic进行分类的,生产者生产消息,消费者消费消息,都是面向Topic的,下面这篇文章主要给大家介绍了关于Kafka Producer中消息缓存模型的相关资料,需要的朋友可以参考下
    2022-04-04
  • Java获取中文拼音、中文首字母缩写和中文首字母的示例

    Java获取中文拼音、中文首字母缩写和中文首字母的示例

    本文主要介绍了Java获取中文拼音、中文首字母缩写和中文首字母,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-10-10
  • Java MyBatis之Mapper代理详解

    Java MyBatis之Mapper代理详解

    这篇文章主要介绍了Java web中MyBatis的mapper代理,文中有详细的代码示例,具有一定的参考价值,感兴趣的小伙伴可以参考一下
    2023-04-04
  • 解决idea使用过程中让你觉得不爽的一些问题(小结)

    解决idea使用过程中让你觉得不爽的一些问题(小结)

    这篇文章主要介绍了解决idea使用过程中让你觉得不爽的一些问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08

最新评论