java零拷贝zero copy MappedByteBuffer

目录

调用操作系统的 mmap

未使用 mmap 的文件通过网络传输的过程

使用 mmap 的文件通过网络传输的过程

使用例子

调用操作系统的 sendfile()

在 java 中的具体实现

mmap的优劣

mmap 的不足

mmap 的优点

mmap 的使用场景


对于零拷贝(zero copy),目前操作系统支持多种方式,具体如下

调用操作系统的 mmap

在之前的页缓存文章的基础上

https://blog.csdn.net/zlpzlpzyd/article/details/135317588

如果在 linux 上如果直接对 page cache 怎么办?

鉴于 java 语言是建立在 jvm 基础上调用操作系统的 api 来对机器资源进行访问的,可以通过 mmap 来实现,从 java 1.4 开始提供了 FileChannel 的 map() 来实现这个功能,这样就可以类似指针的方式来直接操作文件了。这样带来的好处是,不用进行用户态和内核态的切换了,减少了机器的资源开销。

未使用 mmap 的文件通过网络传输的过程

可见发生了4次用户态与内核态的上下文切换(调用 read()后返回数据与调用write()后返回数据),4次数据拷贝(两次DMA拷贝,两次CPU拷贝)。
传统的IO性能是非常差的,所以,要想提高文件传输的性能,就需要减少用户态与内核态的上下文切换和内存拷贝的次数。

使用 mmap 的文件通过网络传输的过程

需要 4 次上下文切换,因为系统调用还是 2 次。但是拷贝从4次变成了3次。

使用例子

java 中通过 MappedByteBuffer 来实现直接对 page cache 的操作。

import java.io.IOException;
import java.io.Serializable;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;


public class TestMapMemeryBuffer2 implements Serializable {

    private final static String CONTENT = "Zero copy implemented by MappedByteBuffer";
    private final static String FILE_NAME = "mmap.txt";

    public static void main(String[] args) throws IOException {
        xieshuju();
        dushuju();
    }
    public static void xieshuju() throws IOException {
        /**写文件数据
         * 打开文件通道 fileChannel 并提供读权限、写权限和数据清空权限,通过 fileChannel 映射到一个可写的内存缓冲区 mappedByteBuffer,
         * 将目标数据写入 mappedByteBuffer,通过 force() 方法把缓冲区更改的内容强制写入本地文件。
         */
        Path path = Paths.get("E:/data",FILE_NAME);
        if (Files.notExists(path)) {
            Files.createDirectories(path.getParent());
            Files.createFile(path);
        }
        byte[] bytes = CONTENT.getBytes(StandardCharsets.UTF_8);
        try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ,
                StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING)) {
            MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, bytes.length);
            if (mappedByteBuffer != null) {
                mappedByteBuffer.put(bytes);
                mappedByteBuffer.force();
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }



    public static void dushuju() throws IOException {
        /**
         * 读文件数据:打开文件通道 fileChannel 并提供只读权限,通过 fileChannel 映射到一个只可读的内存缓冲区 mappedByteBuffer,
         * 读取 mappedByteBuffer 中的字节数组即可得到文件数据。
         * */
        Path path = Paths.get("E:/data",FILE_NAME);
        if (Files.notExists(path)) {
            Files.createDirectories(path.getParent());
            Files.createFile(path);
        }
        int length = CONTENT.getBytes(StandardCharsets.UTF_8).length;
        try (FileChannel fileChannel = FileChannel.open(path, StandardOpenOption.READ)) {
            MappedByteBuffer mappedByteBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, length);
            if (mappedByteBuffer != null) {
                byte[] bytes = new byte[length];
                mappedByteBuffer.get(bytes);
                String content = new String(bytes, StandardCharsets.UTF_8);
                System.out.println(content);
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}

调用操作系统的 sendfile()

在 Linux 内核版本 2.1 中,提供了1个专门发送文件的系统调用函数 sendfile()。

它可以替代前面的 read() 和 write() 这两个系统调用,这样就可以减少1次系统调⽤,文件传输变为在操作系统执行,不需要应用程序的参与,也就减少了 2 次上下文切换的开销。

这样就只有 2 次上下文切换,和 3 次数据拷贝。

在 java 中的具体实现

FileChannel 的 transferFrom() 和 transferTo()。

两者使用调用方式不同,transferFrom() 是目标 FileChannel 调用,transferTo() 是源 FileChannel 调用。

https://blog.csdn.net/weixin_44371237/article/details/122322890

以上的还不是真正的零拷贝技术,如果网卡支持 SG-DMA(The Scatter-Gather DirectMemory Access)技术(和普通的 DMA 有所不同),可以减少通过 CPU 把内核缓冲区的数据拷贝到 socket 缓冲区的过程。

Linux运行这条命令查看网卡是否支持 SG-DMA

$ ethtool -k eth0 | grep scatter-gather
scatter-gather: on

这样,最终只有2次上下文切换和2 次数据拷贝。

mmap的优劣

mmap 的不足

鉴于操作系统的 page cache 为 4KB,所以在使用过程中最好是 4KB 的整数倍,不然会造成内存空间浪费。

map方法中 size 的类型是 long,但是在注释中指定不能大于 Integer#MAX_VALUE,也就是2147483647字节,换算一下大概是2G。也就是说 MappedByteBuffer 的最大值是2G,一次最多只能 map 2G 的数据。

由于 MappedByteBuffer 最终的实现类为 DirectByteBuffer,即使用了堆外内存,这就使得在使用的时候对内存回收时变得困难。
如果针对大文件使用 MappedByteBuffer,会造成内存不足的情况,其他一些经常使用的文件会造成经常被回收的情况(因为 page cache 的在操作系统实现了 lru 算法来处理)。

mmap内存映射的大小始终是整数页,因此对于文件实际大小和映射的空间之间多少会有差异,这个差异的空间是被浪费的,对于小文件来说这个浪费比例被放大,因此 mmap 更适合频繁操作的大文件。频繁映射大量不同大小的内存,会导致内存碎片化。

针对大文件的传输,不应该使用 Page Cache,也就是说不应该使用零拷贝技术,因为可能由于 Page Cache 被大文件占据,由于大文件难以命中 Page Cache 缓存,导致热点小文件无法命中 Page Cache,这样在高并发的环境下,会带来严重的性能问题。

传输大文件的时候,使用异步 IO + 直接 IO,因为可以绕过 Page Cache
传输小文件的时候,使用零拷贝技术
 

针对所谓的文件大小的定义,需要通过压力测试来验证一下,这个需要后面看一下。

MappedByteBuffer 是没有close方法的,即使它的 FileChannel 被close了,MappedByteBuffer 仍然处于打开状态,只有JVM进行垃圾回收的时候才会被关闭。而这个时间是不确定的。

对于具体的写入磁盘时间是由操作系统来决定的,如果想要马上写入磁盘需要手动调用 force()。

mmap 的优点

mmap基于操作系统的 mmap 的内存映射技术,通过 MMU 映射文件,将文件直接映射到用户态的内存地址,使得对文件的操作不再是 write/read,而转化为直接对内存地址的操作,使随机读写文件和读写内存相似的速度。

把文件映射到用户空间里的虚拟内存,省去了从内核缓冲区复制到用户空间的过程,文件中的位置在虚拟内存中有了对应的地址,可以像操作内存一样操作这个文件,这样的文件读写文件方式少了数据从内核缓存到用户空间的拷贝,效率很高。

将用户态和内核态的重操作减少了。

mmap 的使用场景

频繁操作的文件,因为是基于 page cache 实现的,主要将磁盘的文件暂时缓存到内存中。如果只是用一次或者次数很少,放在内存里没有必要。

参考链接

https://blog.csdn.net/alex_xfboy/article/details/90174840

https://blog.csdn.net/bookssea/article/details/122099186

https://blog.csdn.net/qq_45038038/article/details/134975039

https://blog.csdn.net/qq_39668099/article/details/130240286

https://juejin.cn/post/6921977140946845704

https://blog.csdn.net/m0_50662680/article/details/128420713

https://www.cnblogs.com/flydean/p/io-nio-mappedbytebuffer.html

https://blog.csdn.net/yzh_1346983557/article/details/119760911

https://www.cnblogs.com/sky-heaven/p/16280797.html

https://mp.weixin.qq.com/s/oPv1-wrhYjiOC1o0M0tjMA

https://www.cnblogs.com/jmcui/p/15256464.html

https://www.cnblogs.com/liujinhui/p/15847633.html

https://zhuanlan.zhihu.com/p/377237946

https://blog.csdn.net/andybegin/article/details/129304899

https://blog.csdn.net/dyuan134/article/details/130126955

https://zhuanlan.zhihu.com/p/54762255

https://tech.meituan.com/2017/05/19/about-desk-io.html

https://www.jianshu.com/p/59dad2d290a1

https://www.jianshu.com/p/c83fa8bd564f

https://blog.csdn.net/NF_ALONG/article/details/129399559

https://zhuanlan.zhihu.com/p/439380628

https://blog.csdn.net/xystrive/article/details/125692926

https://zhuanlan.zhihu.com/p/607416958

https://zhuanlan.zhihu.com/p/665075935

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/283127.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

LVGL 在framebuffer设备上的移植

LVGL 在framebuffer设备上的移植 ItemDescDate2023-12-31Authorhongxi.zhuplatformNXP I.MX6ULLLCDSPI TFTLCD NV3030B 文章目录 LVGL 在framebuffer设备上的移植一、LVGL源码获取二、源码修改适配三、编译&运行补充 一、LVGL源码获取 新建lvgl_imx6ull文件夹&#xff0c…

【基础】【Python网络爬虫】【10.验证码处理】OCR识别,Tesseract ,ddddocn识别,打码平台,滑块验证码(附大量案例代码)(建议收藏)

Python网络爬虫基础 验证码处理一. OCR识别1. Tesseract 引擎的安装windows引擎环境安装Mac系统引擎环境安装安装 tesseract查看 tesseract 版本安装过程遇到的报错解决方法下载中文包中文包存放目录查看全部语言库python 安装 pytesseract 和 pillow识别图片中文字体 Linux系统…

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#)

Baumer工业相机堡盟工业相机如何通过NEOAPI SDK设置相机本身的数据保存(CustomData)功能(C#) Baumer工业相机Baumer工业相机的数据保存(CustomData)功能的技术背景CameraExplorer如何使用图像剪切&#xff…

【42页动态规划学习笔记分享】动态规划核心原理详解及27道LeetCode相关经典题目汇总

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推荐--…

MIT线性代数笔记-第35讲-期末复习

目录 35.期末复习打赏 35.期末复习 已知一个矩阵 A A A满足 A x ⃗ [ 1 0 0 ] A \vec{x} \begin{bmatrix} 1 \\ 0 \\ 0 \end{bmatrix} Ax ​100​ ​无解且 A x ⃗ [ 0 1 0 ] A \vec{x} \begin{bmatrix} 0 \\ 1 \\ 0 \end{bmatrix} Ax ​010​ ​仅有一个解 (1)求 A A A的…

Linux驱动学习—pinctl和gpio子系统

1、pinctl和gpio子系统&#xff08;一&#xff09; 1.1pinctrl 子系统主要工作内容 <1>获取设备树中 pin 信息&#xff0c;管理系统中所有的可以控制的 pin&#xff0c; 在系统初始化的时候&#xff0c; 枚举所有可以控制的 pin&#xff0c; 并标识这些 pin。 <2>…

burpsuite模块介绍之compare

导语 Burp Comparer是Burp Suite中的一个工具&#xff0c;主要提供一个可视化的差异比对功能&#xff0c;可以用于分析比较两次数据之间的区别。它的应用场景包括但不限于&#xff1a; 枚举用户名过程中&#xff0c;对比分析登陆成功和失败时&#xff0c;服务器端反馈结果的区…

python脚本实现一次提取多个文件下的图片

problem formulation 有时候下载的数据集如下&#xff0c;就很烦&#xff0c;一个里面就一张图片 code import os import shutil# 定义源目录和目标目录 source_dir ./dataset/data/Detection destination_dir ./dataset/data/img# 确保目标目录存在&#xff0c;如果不存…

初识大数据,一文掌握大数据必备知识文集(7)

&#x1f3c6;作者简介&#xff0c;普修罗双战士&#xff0c;一直追求不断学习和成长&#xff0c;在技术的道路上持续探索和实践。 &#x1f3c6;多年互联网行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f389;欢迎 &#x1f44d;点赞✍评论…

pycharm python环境安装

目录 1.Python安装 2.PyQt5介绍 3.安装pyuic 4.启动designer.exe 5.pyinstaller(打包发布程序) 6.指定源安装 7.PyQt5-tools安装失败处理 8.控件介绍 9.错误记录 1.NameError: name reload is not defined 10.开发记录 重写报文输出和文件 ​编辑 1.Python安装 点…

BFS

目录 BFS 走迷宫 BFS 算法特点 优先考虑宽度&#xff0c;换句话说就是按层推进&#xff0c;直到最后一层。 空间复杂度&#xff1a;O&#xff08;2^h&#xff09; BFS是按宽度搜索&#xff0c;所以可以找到最短路&#xff0c;适用于解决像最短路&#xff0c;最少之类的问题…

Python装饰器的专业解释

装饰器&#xff0c;其实是用到了闭包的原理来进行操作的。 单个装饰器&#xff1a; 以下是一个简单的例子&#xff1a; def outer(func):print("OUTER enter ...")def wrapper(*args, **kwargs):print("调用之前......")result func(*args, **kwargs)p…

【YOLO系列】yolo V1 ,V3,V5,V8 解释

文章目录 yolo V1 模型结构图通道数 的 物理意义是什么&#xff1f;输出 7730 怎么理解&#xff1f;YOLO v1 损失函数LOSS yolo V3yolo V5yolo V8 视频来源&#xff1a;https://www.bilibili.com/video/BV13K411t7Zs/ AI视频小助理 一、YOLO系列的目标检测算法&#xff0c;其中…

【操作系统】存储器管理

目录 4.1 存储器的层次结构 4.1.1 多级存储结构 4.1. 2 可执行存储器 4.1.3 高速缓存和磁盘缓存 4.2 程序的装入和链接 4.2.1 程序的装入 4.2.2 程序的链接 1.静态链接(Static Linking)方式 (1) 对相对地址进行修改。 (2) 变换外部调用符号。 2. 装入时动态链接(Load-t…

CodeWave赋能创新的全功能技术平台

目录 前言1 应用中心2 资产中心&#xff1a;汇聚创新能量&#xff0c;提供开发加速3 集成中心3.1 API管理3.2 报表管理 4 运维中心4.1 资源监控4.2 用户管理4.3 权限管理4.4 日志与监控 5 配置中心5.1 源码配置5.2 镜像仓库配置5.3 数据库配置5.4 报表配置5.5 资产配置5.6 品牌…

JavaFX:MVC模式学习01-使用PropertyValueFactory将模型与视图绑定

PropertyValueFactory类是“TableColumn cell value factory”,绑定创建列表中的项。示例如下&#xff1a; TableColumn<Person,String> firstNameCol new TableColumn<Person,String>("First Name");firstNameCol.setCellValueFactory(new PropertyVal…

安装torch(GPU版本)并在Pycharm中配置

零.前置环境 1.NVIDIA GPU Computing Toolkit已安装 版本为&#xff1a;11.6 已添加到环境变量 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\libnvvp 在cmd中查看cuda版本 方法1&#xff1a…

详解Vue3中的鼠标事件mousemove、mouseover和mouseout

本文主要介绍Vue3中的常见鼠标事件mousemove、mouseover和mouseout。 目录 一、mousemove——鼠标移动事件二、mouseover——鼠标移入事件三、mouseout——鼠标移出事件 下面是Vue 3中常用的鼠标事件mousemove、mouseover和mouseout的详解。 一、mousemove——鼠标移动事件 鼠…

图神经网络--GNN从入门到精通

图神经网络--GNN从入门到精通 一、图的基本表示和特征工程1.1 什么是图1.2 图的基本表示1.3 图的性质--度&#xff08;degree)1.4 连通图&#xff0c;连通分量1.5有向图连通性1.6图直径1.7度中心性1.7特征中心性&#xff08; Eigenvector Centrality&#xff09;1.8中介中心性 …

年度总结 | 回味2023不平凡的一年

目录 前言1. 平台成就2. 自我提升3. Bug连连4. 个人展望 前言 每年CSDN的总结都不能落下&#xff0c;回顾去年&#xff1a;年度总结 | 回味2022不平凡的一年&#xff0c;在回忆今年&#xff0c;展望下年 1. 平台成就 平台造就我&#xff08;我也造就平台哈哈&#xff09; 每…