MappedByteBuffer内存(堆外)文件映射

在linux中tmpfs是一种可以把内存直接拿来当文件系统使用的一种技术,这一技术也是共享内存/mmap的实现基础。今天我们就来研究一下java中如何使用mmap。

从JDK 1.4版本开始,Java内存映射文件(Memory Mapped Files)就已经在java.nio包中,引入NIO后,Java IO已经相当快,而且内存映射文件提供了Java有可能达到的最快IO操作,这也是为什么那些高性能Java应用应该使用内存映射文件来持久化数据。

IO一直是那些高性能系统的一个主要关注点,内存映射文件允许你使用direct(DirectByteBuffer)或者non-direct 字节缓存(HeapByteBuffer)来直接读写内存。内存映射文件的一个关键优势是操作系统负责真正的读写,即使你的程序在刚刚写入内存后就挂了,操作系统仍然会将内存中的数据写入文件系统。另外一个更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。

1、什么是Java内存映射文件/IO

内存映射文件是一种允许Java程序直接从内存访问的特殊文件。通过将整个文件或者文件的一部分映射到内存中、操作系统负责获取页面请求和写入文件,应用程序就只需要处理内存数据,这样可以实现非常快速的IO操作。而且用于内存映射文件的内存在Java的堆空间以外。Java中的java.nio包支持内存映射文件,可以使用MappedByteBuffer来读写内存。

 

2、示例:

下面的例子演示了如何使用内存映射文件来读写。我们使用RandomAccessFile打开文件并使用FileChannel的map()方法将它映射到内存,map()方法有三个输入参数:mode, position, size。返回值MappedByteBuffer是用来处理内存映射文件的字节缓存。

package mmap;
import java.io.RandomAccessFile;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

public class MmapTest {
	private static int count = 10*1024*1024; // 10 MB

	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		RandomAccessFile memoryMappedFile = new RandomAccessFile("D:\\largeFile.txt", "rw");

		// Mapping a file into memory
		MappedByteBuffer out = memoryMappedFile.getChannel().map(
FileChannel.MapMode.READ_WRITE, 0, count);

		// Writing into Memory Mapped File
		for (int i = 0; i < count; i++) {
			out.put((byte) 'A');
		}
		System.out.println("Writing to Memory Mapped File is completed");

		// reading from memory file in Java
		for (int i = 0; i < 10; i++) {
			System.out.print((char) out.get(i));
		}
		System.out.println("Reading from Memory Mapped File is completed");

		memoryMappedFile.close();
	}
}

 

 说明:

  • Java语言通过java.nio包支持内存映射文件和IO。
  • 内存映射文件用于对性能要求高的系统中,它可以将整个文件或一部分加载到内存中;
  • 如果被请求的页面不在内存中,内存映射文件会导致页面错误
  • 将一个文件区间映射到内存中的能力取决于内存的可寻址范围,这个范围的最大值是Integer.MAX_VALUE,即2的31次方-1 。
  • Java中的内存映射文件比流IO要快(译注:对于大文件而言是对的,小文件则未必)
  • 用于加载文件的内存在Java的堆内存之外,存在于共享内存中,允许两个不同进程访问文件。注意,这依赖于你用的是direct还是non-direct字节缓存。
  • 读写内存映射文件是操作系统来负责的,因此,即使你的Java程序在写入内存后就挂掉了,只要操作系统工作正常,数据就会写入磁盘。
  • Direct字节缓存比non-direct字节缓存性能要好;
  • 不要经常调用MappedByteBuffer.force()方法,这个方法强制操作系统将内存中的内容写入硬盘,所以如果你在每次写内存映射文件后都调用force()方法,你就不能真正从内存映射文件中获益,而是跟disk IO差不多。
  • 如果电源故障或者主机瘫痪,有可能内存映射文件还没有写入磁盘,意味着可能会丢失一些关键数据。
  • MappedByteBuffer和文件映射在缓存被GC之前都是有效的。sun.misc.Cleaner可能是清除内存映射文件的唯一选择。

参考:

https://blog.csdn.net/napolunyishi/article/details/18214929

https://www.cnkirito.moe/mq-million-queue/

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以使用Java的RandomAccessFile类结合MappedByteBuffer来指定位置写入文件。下面是一个示例代码: ```java import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; public class FileWriteExample { public static void main(String[] args) { try { // 创建一个RandomAccessFile对象,指定文件路径和打开方式(这里以读写方式打开) RandomAccessFile file = new RandomAccessFile("example.txt", "rw"); // 获取文件通道 FileChannel channel = file.getChannel(); // 创建MappedByteBuffer,指定映射模式、起始位置和映射大小 MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, 10); // 写入数据到指定位置 buffer.position(5); // 设置写入位置为第5个字节 buffer.put("Hello".getBytes()); // 写入数据 // 关闭文件通道和RandomAccessFile对象 channel.close(); file.close(); System.out.println("数据写入成功!"); } catch (Exception e) { e.printStackTrace(); } } } ``` 在上述示例中,我们首先创建一个RandomAccessFile对象,并指定文件路径和读写方式。然后,我们获取文件通道,并使用`map()`方法创建一个MappedByteBuffer对象,指定映射模式为读写,起始位置为0,映射大小为10字节。 接下来,我们通过调用`position()`方法将写入位置设置为第5个字节,然后使用`put()`方法将数据写入到缓冲区。 最后,我们关闭文件通道和RandomAccessFile对象,并输出写入成功的消息。 请注意,在使用MappedByteBuffer时,需要确保文件已经存在或者隐式创建了一个空文件。此外,还需要注意内存映射的大小不能超过文件的大小。 希望这个示例能帮助到你!如果你还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值