一文彻底弄懂零拷贝原理以及java实现

一文彻底弄懂零拷贝原理以及Java实现

什么是零拷贝

在传统的计算机系统中,在文件从磁盘到达应用程序之前,文件会被存储到内核缓冲区中。当应用程序需要访问文件时,它必须从内核缓冲区将文件读入应用程序的缓冲区。这种方式称之为“传统的拷贝方式”。

但是,“传统的拷贝方式”存在以下问题:

  1. 内存中存在多个拷贝:原始数据的一个拷贝保存在磁盘中,一个拷贝保存在内核缓冲区中,另一个拷贝保存在应用程序缓冲区中。
  2. 额外的 CPU 开销:每当一个进程读写文件时,内核必须从内核缓冲区向进程缓冲区复制数据,这需要 CPU 资源。
  3. 多个拷贝增加了上下文切换:多个拷贝需要上下文切换,同时也会增加网络、存储设备、操作系统之间的交互,这都会导致数据不连续,效率低下。

为了解决这些问题,Linux 系统中引入了彻底的零拷贝技术。这样一来,用户空间的应用程序可以直接访问内核缓冲区中的数据,避免了不必要的拷贝将数据发送给网络和存储设备。

两种实现零拷贝的方式

介绍一下实现零拷贝的两种常见方式:文件描述符传递(sendfile)和内存映射文件(mmap)。

文件描述符传递(sendfile)

“文件描述符传递”利用两个系统调用 —— sendfile 和 splice。简单来说,sendfile 属于 posic/ansi 标准,而 splice 属于 unix 标准,它们都能够减少 CPU 的消耗并避免数据拷贝。

sendfile 函数是把一个文件描述符中的数据传到另一个文件描述符中,它调用 sendfile 函数的文件描述符可以是 socket 或者是普通文件。一旦 socket 和 file 都打且准备好了,数据就可以通过 Socket 并使用 TCP 协议传输。

splice 函数可以把两个管道中数据传输。使用 splice() 函数的优点是在数据移动时不需要将数据从内核空间移动到用户空间,再从用户空间移动到新的文件描述符。splice 可以直接从一个文件描述符移动到另一个文件描述符。splice 功能上和“内存映射文件”有一定的类似之处,它们都是可以避免数据在用户空间和内核空间来回拷贝。

示例:

public static void sendFileBySendFile(File file, OutputStream os) throws IOException {
    try (FileInputStream fis = new FileInputStream(file); FileChannel channel = fis.getChannel()) {
        long length = file.length();
        WritableByteChannel wChannel = Channels.newChannel(os);
        channel.transferTo(0, length, wChannel);
    }
}

内存映射文件(mmap)

mmap() 系统调用是将一个文件或者其他对象映射到内存中,通常是将一个文件映射到被调用进程的地址空间中,从而可以直接访问文件。内存映射文件的实现可以无需再次拷贝数据,减少了 I/O 操作和消耗。

当进程请求一段文件的内存映射时,内核会以页(通常为 4KB )为单位来设置映射。

映射区域可以当作是文件的缓存,内核也会根据内存写入数据情况而实时刷写到磁盘上。如此一来,进程就可以避免来回复制数据。这里的零拷贝是多个客户端或者系统之间的零拷贝,并不是零次拷贝。

示例:

BufferedInputStream in = new BufferedInputStream(new FileInputStream(new File(filePath)));
FileChannel infileChannel = new FileInputStream(new File(filePath)).getChannel();
MappedByteBuffer buffer = infileChannel.map(FileChannel.MapMode.READ_ONLY, 0, infileChannel.size());

总结

通过零拷贝技术,我们可以让磁盘、网络等协作更高效,在数据的读写和处理方面带来好处。在一些高性能在线服务的场景下,零拷贝技术的优势得以更好的体现。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:一文彻底弄懂零拷贝原理以及java实现 - Python技术站

(0)
上一篇 2023年6月28日
下一篇 2023年6月28日

相关文章

  • 【前端基础】动态脚本与JSONP

    【前端基础】动态脚本与JSONP 在前端开发中,动态脚本和JSONP是两个非常重要的概念,它们可以帮助我们更好地构建Web应用。本文将介绍这两个概念,以及如何在实际开发中使用它们。 动态脚本 动态脚本是指在客户端动态加载、执行的JavaScript脚本。在传统的静态页面中,所有的脚本都是在HTML中直接写出来的,但是当我们面对一些复杂的业务逻辑时,需要动态地…

    其他 2023年3月28日
    00
  • matplotlib:图片与子片 调整子图周围的间距

    Matplotlib: 调整子图周围的间距 Matplotlib是一个用于绘制数据可视化图表的Python库。在Matplotlib中,我们可以使用子图来在同一个图中绘制多个子图。在某些情况下,我们可能需要调整子图周围的间距。本攻略将介绍如何在Matplotlib中调整子图周围的间距。 步骤一:导Matplotlib库 在使用Matplotlib之前,我们导…

    other 2023年5月9日
    00
  • iPhone11怎么强制重启?iPhone11/11pro强制重启图文教程

    iPhone11怎么强制重启? 如果你的iPhone11或iPhone11 Pro在使用过程中出现卡死、屏幕黑屏或无响应等问题,你可以尝试强制重启来解决问题。下面是iPhone11/11Pro强制重启的图文教程。 步骤一:按住侧边按键+音量控制键 在进行强制重启前,请确保你的iPhone11或iPhone11Pro已经连接充电器或电脑并且有足够的电量。否则可…

    other 2023年6月26日
    00
  • sas的scan函数

    当然,我可以为您提供有关“SAS的SCAN函数”的完整攻略,以下是详细说明: SAS的SCAN函数 SAS的SCAN函数用于提取字符串中的单词。它根据指定的分隔符将字符串割多个单词,并返回指定位置的单词。以下是SCAN函数的语法: SCAN(string position, delimiter) 其中,string是分割字符串,position是要返回的单词…

    other 2023年5月7日
    00
  • java基础之pdf文件的合并

    Java基础之PDF文件的合并 在Java中,我们可以使用iText库来合并PDF文件。iText是一个开源的Java PDF库,可以用于创建、修改和处理PDF文件。本攻略将介如何使用iText库来合并PDF文件。 步骤1:导入iText库 首先,我们需要在Java项目中导入iText库。可以通过Maven或手动下载jar包的方式导入iText库。以下是使用…

    other 2023年5月9日
    00
  • powerdesigner使用教程(很具体 很实用)

    PowerDesigner使用教程(很具体 很实用) PowerDesigner是一款流程设计和建模工具,被广泛应用于企业级数据建模、过程建模、业务建模、软件建模等各个领域。本篇教程将详细介绍PowerDesigner的基本使用方法,帮助初学者快速上手。 PowerDesigner基本介绍 PowerDesigner目前有两个版本,分别是标准版和专业版,其中…

    其他 2023年3月28日
    00
  • Yarn与Lerna管理monorepo使用详解

    Yarn与Lerna管理monorepo使用详解 什么是monorepo monorepo是一种代码管理策略,即将多个相关的项目放在一个代码仓库中进行管理。相比于多个单独仓库管理,monorepo管理具有如下优势: 可以避免模块版本同步的问题; 可以方便地重构代码; 可以方便地共享代码; 可以提高代码重用率; 可以提高团队间的协作效率。 Yarn和Lerna…

    other 2023年6月27日
    00
  • postman自定义函数实现 时间函数的思路详解

    Postman自定义函数实现时间函数的思路详解 Postman是一款常用的API开发和测试工具,它提供了自定义函数的功能,可以通过编写JavaScript代码来扩展其功能。下面是实现时间函数的思路详解。 步骤一:创建自定义函数 首先,在Postman中创建一个自定义函数,用于实现时间相关的功能。可以通过以下步骤创建: 打开Postman应用程序。 在左侧导航…

    other 2023年7月29日
    00
合作推广
合作推广
分享本页
返回顶部