首页 > 编程语言 >聊聊Java中的mmap

聊聊Java中的mmap

时间:2023-04-14 09:37:06浏览次数:33  
标签:文件 Java 映射 mmap 访问 内存 聊聊

mmap是什么

当我们读取或修改大文件时,传统的文件I/O操作可能会变得很慢,这时候mmap就可以派上用场了。mmap(Memory-mapped files)是一种在内存中创建映射文件的机制,它可以使我们像访问内存一样访问文件,从而避免频繁的文件I/O操作。

使用mmap的方式是在内存中创建一个虚拟地址,然后将文件映射到这个虚拟地址上。这个映射的过程是由操作系统完成的,它会将文件中的数据按需加载到内存中,而不是一次性加载整个文件。这样,我们可以通过指针操作这个虚拟地址,就像访问内存一样来读取或者修改文件内容。

与传统的文件I/O操作相比,mmap具有以下几个优点:

  1. 避免频繁的文件I/O操作:通过将文件映射到内存中,我们可以避免频繁的文件I/O操作,从而提高读取或修改文件的效率。
  2. 减少内存的使用:mmap只会将文件中需要访问的部分加载到内存中,而不是一次性加载整个文件,这样可以减少内存的使用,提高系统的性能。
  3. 支持多进程访问:mmap创建的虚拟地址在所有进程中都是可访问的,因此可以支持多个进程同时访问同一个文件。
  4. 支持文件的共享:由于mmap支持多进程访问,所以多个进程可以共享同一个文件的内容,从而减少内存的使用,提高系统的性能。
  5. 支持随机访问:由于mmap创建的虚拟地址可以像访问内存一样随机访问,因此可以支持随机访问文件,从而提高文件访问的效率。

总之,mmap是一种非常有效的文件访问方式,它可以帮助我们避免频繁的文件I/O操作,减少内存的使用,支持多进程访问和文件的共享,支持随机访问等等,因此在处理大文件时非常有用。

Java中的mmap

在Java中,mmap是通过使用Java NIO(New I/O)的ByteBuffer实现的。当使用mmap映射文件时,Java会通过JNI(Java Native Interface)调用操作系统提供的mmap函数,将文件映射到虚拟地址空间中。在 Java 中,mmap 技术主要使用了 Java NIO (New IO)库中的 FileChannel 类,它提供了一种将文件映射到内存的方法,称为 MappedByteBuffer。MappedByteBuffer 是 ByteBuffer 的一个子类,它扩展了 ByteBuffer 的功能,可以直接将文件映射到内存中。

下面我们来看一个使用 mmap 的简单示例。假设我们有一个 1GB 大小的文件,我们可以将其映射到内存中:

File file = new File("data.txt");
long fileSize = file.length();
MappedByteBuffer mappedByteBuffer = new RandomAccessFile(file, "rw").getChannel()
        .map(FileChannel.MapMode.READ_WRITE, 0, fileSize);

上述代码中,我们使用 RandomAccessFile 类打开文件,并将其映射到内存中。通过 getChannel() 方法获取文件通道,再调用 map() 方法将文件映射到内存中。其中,第一个参数指定映射模式(READ_WRITE 表示可读可写),第二个参数指定映射的起始位置,第三个参数指定映射的长度。

一旦文件被映射到内存中,我们就可以像操作普通的 ByteBuffer 一样来操作它,例如读取和写入数据:

// 读取数据
byte[] buffer = new byte[1024];
mappedByteBuffer.get(buffer);

// 写入数据
byte[] data = "Hello, world!".getBytes();
mappedByteBuffer.put(data);

需要注意的是,由于 mmap 技术将文件映射到内存中,因此操作映射文件时需要特别小心,需要考虑文件长度和操作系统的限制,以免超出系统限制导致操作失败,否则可能会导致文件损坏或数据丢失。为了确保数据的完整性,我们通常需要在操作映射文件之前先将其全部加载到内存中,待操作完成后再将其刷回磁盘。这可以通过调用 MappedByteBuffer 的 load() 和 force() 方法来实现:

// 将文件全部加载到内存中
mappedByteBuffer.load();

// 将修改的数据刷回磁盘
mappedByteBuffer.force();

这里需要注意,mmap映射的文件是直接映射到内存中的,因此需要注意内存使用情况,以免导致内存泄漏或OOM异常。因此,在使用mmap技术时,我们需要注意一些最佳实践,例如避免将过多的数据映射到内存中,并在使用完缓冲区后及时释放资源。

此外,mmap 技术还可以用于实现多个进程之间共享内存数据。如果一个进程将文件映射到内存中,并对其进行修改,其他进程也可以看到这些修改。这种方法比传统的进程间通信方式更加高效,因为多个进程可以直接共享内存数据,而无需通过操作系统来传输数据。

mmap小结

mmap 是一种常用于文件读取和写入的系统调用。在 Linux 系统中,mmap 通过将文件映射到进程的虚拟地址空间中来实现对文件的操作,这意味着在内存中,文件的内容就像被放置在了一块连续的内存区域中一样。

mmap 的原理是将一个文件或者其它对象映射到进程的地址空间中,这样就可以直接对内存进行读写操作,从而省去了繁琐的读写文件的操作。mmap 的实现方式是将文件读取到内核的页缓存中,然后将这些页映射到进程的虚拟地址空间中。当进程通过指针对这些页进行访问时,就可以直接读写文件。

mmap 的优势在于它可以大大提高文件的读写效率,尤其是在读取大文件时,可以避免在内存中创建额外的缓冲区,从而提高程序的效率。但是需要注意的是,使用 mmap 读写文件时需要特别小心,因为这种方式对内存的使用非常敏感,一旦出现问题可能会导致程序的崩溃。

对于Java开发人员来说,理解和掌握mmap技术对于优化程序性能和提高IO操作效率非常重要。

标签:文件,Java,映射,mmap,访问,内存,聊聊
From: https://www.cnblogs.com/caicz/p/17317267.html

相关文章

  • 使用java.util.zip对生成的字节数组输出文件流 进行打包压缩(单个、批量),并返回压缩包
    废话不多说直接上代码 packagegov.test.util;importjava.io.ByteArrayInputStream;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.util.List;importjava.util.Map;importorg.apache.tools.zip.ZipEntry;importorg.apache.tools.zip.Zip......
  • kettle从入门到精通 第十二课 kettle java代码过滤记录、利用Janino计算Java表达式
    1、下图通过简单的示例讲解了根据java代码过滤记录和利用Janino计算Java表达式两个组件。   2、根据java代码过滤记录1)步骤名称:自定义2)接收匹配的行的步骤(可选):下面条件(java表达式)执行结果为true时流转的步骤3)接收不匹配的行的步骤(可选):下面条件(java表达式)执行结果......
  • java.lang.OutOfMemoryError- unable to create new native thread 问题排查
    问题描述最近连续两天大约凌晨3点,线上服务开始异常,出现OOM报错。且服务所在的物理机只能ping通,但是无法登录。报错信息如下:ERROR04-1203:01:43,930[DefaultQuartzScheduler_Worker-3]JobRunShell[JobRunShell]:211JobthrewanunhandledException:java.lang.OutOfMemory......
  • 02_JAVA匿名内部类
    匿名对象就是没有名字的对象匿名对象的应用场景A:调用方法,仅仅只调用一次的时候。(调用多次的时候不适合,且匿名对象调用完毕就是垃圾,可以被回收器回收)//newStudent().show();B:匿名对象可以作为实际参数传递。StudentDemosd=newsStudentDemo();//Studentss=newSt......
  • Java基础知识点内部类之成员内部类
    一:概述1.成员内部类顾名思义就是写在成员位置的,属于外部类成员。2.成员变量可以被一些修饰符所修饰,比如:private,default,public,static等。3.在成员内部类中,jdk16之前不能定义静态变量,jdk16开始才可以定义静态变量。二;获取内部类对象方法一;当成员内部类被private修饰时,在外部类中......
  • JAVA生成行程单PDF
    JAVA生成行程单PDF一、pom依赖首先引入PDF需要的pom依赖<!--pdf--><dependency><groupId>com.itextpdf</groupId><artifactId>itextpdf</artifactId><version>5.5.13</version>......
  • java 处理常量字符串过长 & springboot 项目读取 resouces 文件夹下的文件内容
    长字符串起因项目里面有一长串的加密字符串(最长的万多个字符),需要拼接作为参数发送给第三方。如果我们使用枚举定义的话,idea编译的时候就会出现编译报错Error:java:常量字符串过长解决想法网上还有一个说法,说是编译器问题,修改idea工具的编译为eclipse即可......
  • JavaScript 变量、标识符和四则运算
    JavaScript基础第二天变量什么是变量?变量由四个部分组成:1.var:声明变量的关键字2.变量名字1.变量的名字可以包含:字母,数字2.不能以数字开头3.不能使用关键字保留字比如var、if、for、列:web、_001、_number3.等于号=在js中它叫做赋值号4.值,赋值号后面的叫做值(变......
  • java捡基础
    ++与--写在前后有什么区别?++或--写在变量前后有区别?*1.如果不参与运算的话,它们是没有区别。*2.如果参与了运算,区别就是很大了。*参与运算时两者的区别:累加的结果要不要参与本次的运算,(使用累加之后值运算,还是使用累加之前的值进行运算......
  • 使用java实现音乐播放
    使用java实现音乐播放的具体代码调用有参构造器,构造器中传入需要播放的音乐路径,文件需要是.wav格式调用start方法播放音乐,设置为从头开始循环播放暂停调用pause方法暂停,暂停保存当前播放进度的毫秒值继续播放调用recommence方法,会读取刚才保存的音乐播放进度的毫秒值调......