Java nio之内存映射

Java nio之内存映射

介绍

内存映射文件非常特别,它允许Java程序直接从内存中读取文件内容,通过将整个或部分文件映射到内存,由操作系统来处理加载请求和写入文件,应用只需要和内存打交道,这使得IO操作非常快。加载内存映射文件所使用的内存在Java堆区之外。Java编程语言支持内存映射文件,通过java.nio包和MappedByteBuffer 可以从内存直接读写文件。

支持内存映射IO的操作系统大多数主流操作系统比如Windows平台,UNIX,Solaris和其他类UNIX操作系统都支持内存映射IO和64位架构,你几乎可以将所有文件映射到内存并通过JAVA编程语言直接访问。

使用内存映射优缺点

内存映射IO最大的优点可能在于性能,这对于建立高频电子交易系统尤其重要。内存映射文件通常比标准通过正常IO访问文件要快。另一个巨大的优势是内存映 射IO允许加载不能直接访问的潜在巨大文件 。经验表明,内存映射IO在大文件处理方面性能更加优异。尽管它也有不足——增加了页面错误的数目。由于操作系统只将一部分文件加载到内存,如果一个请求 页面没有在内存中,它将导致页面错误。同样它可以被用来在两个进程中共享数据。

Java的内存映射IO的要点

1、java通过java.nio包来支持内存映射IO。
2、内存映射文件主要用于性能敏感的应用,例如高频电子交易平台。
3、通过使用内存映射IO,你可以将大文件加载到内存。
4、内存映射文件可能导致页面请求错误,如果请求页面不在内存中的话。
5、映射文件区域的能力取决于于内存寻址的大小。在32位机器中,你不能访问超过4GB或2 ^ 32(以上的文件)。
6、内存映射IO比起Java中的IO流要快的多。
7、加载文件所使用的内存是Java堆区之外,并驻留共享内存,允许两个不同进程共享文件。
8、内存映射文件读写由操作系统完成,所以即使在将内容写入内存后java程序崩溃了,它将仍然会将它写入文件直到操作系统恢复。
9、出于性能考虑,推荐使用直接字节缓冲而不是非直接缓冲。
10、不要频繁调用MappedByteBuffer.force()方法,这个方法意味着强制操作系统将内存中的内容写入磁盘,所以如果你每次写入内存映射文件都调用force()方法,你将不会体会到使用映射字节缓冲的好处,相反,它(的性能)将类似于磁盘IO的性能。
11、万一发生了电源故障或主机故障,将会有很小的机率发生内存映射文件没有写入到磁盘,这意味着你可能会丢失关键数据。

使用内存映射拷贝文件

public void testMappedByteBuffer1() throws Exception {

    FileInputStream inputStream = new FileInputStream(new File("e:/nio/test.txt"));
    FileChannel inChannel = inputStream.getChannel();
    FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/testcopy.txt"),true);
    FileChannel outChannel = outputStream.getChannel();

    long fileSize = inChannel.size();
    MappedByteBuffer mappedByteBuffer = inChannel.map(MapMode.READ_ONLY, 0, fileSize);

    outChannel.write(mappedByteBuffer);

    System.out.println(System.currentTimeMillis() - start);
    outputStream.close();
    inputStream.close();
}


//这个拷贝方法是有问题的,还没分析出原因?
public void testMappedByteBuffer() throws Exception {

    FileInputStream inputStream = new FileInputStream(new File("e:/nio/ideaIC-15.0.2.exe"));
    FileChannel inChannel = inputStream.getChannel();
    FileOutputStream outputStream = new FileOutputStream(new File("e:/nio/ideaIC-15.0.2Copy.exe"));
    FileChannel outChannel = outputStream.getChannel();

    byte[] bytes = new byte[4 * 1024 * 1024];
    int byteSize = bytes.length;
    long fileSize = inChannel.size();
    MappedByteBuffer mappedByteBuffer = inChannel.map(MapMode.READ_ONLY, 0, fileSize);
    long start = System.currentTimeMillis();
    for (long len = 0; len < fileSize; len = len + byteSize) {
        ByteBuffer buffer = null;
        if (len <= fileSize - byteSize) {
            buffer = mappedByteBuffer.get(bytes);
        }
        if (len > fileSize - byteSize) {
            int length = (int) (fileSize - len);
            buffer = mappedByteBuffer.get(new byte[length]);
        }
        buffer.flip();
        outChannel.write(buffer);
        buffer.clear();
    }
    System.out.println(System.currentTimeMillis() - start);
    outputStream.close();
    inputStream.close();
}

总结

在操作大文件时使用内存映射是有一定优势的,其高效的性能能够带来速度的提升。平时开发遇到场景并不多。

参考

1、https://www.ibm.com/developerworks/cn/java/l-javaio/
2、https://www.ibm.com/developerworks/cn/java/j-nativememory-linux/
3、http://www.oschina.net/translate/10-things-to-know-about-memory-mapped-file-in-java

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值