Java NIO笔记之内存映射文件

大致的原理图如下:
这里写图片描述
FileChannel提供了一个map()的方法,该方法可以在一个打开的文件和一个特殊类型的ByteBuffer之间建立一个虚拟内存映射。在FileChannel上调用map( )方法会创建一个由磁盘文件支持的虚拟内存映射(virtual memory mapping)并在那块虚拟内存空间外部封装一个MappedByteBuffer对象。
MappedByteBuffer类似于一个内存缓冲区,不过数据元素存储在磁盘的文件中,调用get( )方法会从磁盘文件中获取数据,此数据反映该文件的当前内容,即使在映射建立之后文件已经被一个外部进程做了修改。通过文件映射看到的数据同您用常规方法读取文件看到的内容是完全一样的。相似地,对映射的缓冲区实现一个put( )会更新磁盘上的那个文件(假设对该文件您有写的权限),并且您做的修改对于该文件的其他阅读者也是可见的。
通过内存映射机制来访问一个文件会比使用常规方法读写高效得多,甚至比使用通道的效率都高。因为不需要做明确的系统调用,那会很消耗时间。更重要的是,操作系统的虚拟内存可以自动缓存内存页(memory page)。这些页是用系统内存来缓存的,所以不会消耗Java虚拟机内存堆(memory heap)。
文件的映射模式
1.只读映射(READ_ONLY) 只读权限
2.读写映射(READ_WRITE) 读写权限
3.私有(复制写)映射(PRIVATE)通过put( )方法所做的任何修改都会导致产生一个私有的数据拷贝并且该拷贝中的数据只有MappedByteBuffer实例可以看到。该过程不会对底层文件做任何修改,而且一旦缓冲区被施以垃圾收集动作(garbage collected),那些修改都会丢失。尽管写时拷贝的映射可以防止底层文件被修改,您也必须以read/write权限来打开文件以建立MapMode.PRIVATE映射。只有这样,返回的MappedByteBuffer对象才能允许使用put( )方法。
写时拷贝这一技术经常被操作系统使用,以在一个进程生成另一个进程时管理虚拟地址空间(virtual address spaces)。使用写时拷贝可以允许父进程和子进程共享内存页直到它们中的一方实际发生修改行为。在处理同一文件的多个映射时也有相同的优势(当然,这需要底层操作系统的支持)。假设一个文件被多个MappedByteBuffer对象映射并且每个映射都是MapMode.PRIVATE模式,那么这份文件的大部分内容都可以被所有映射共享。
MappedByteBuffer没有unmap()方法,关闭相关联的FileChannel不会破坏映射,只有丢弃缓冲区对象本身才会破坏该映射。一个映射一旦建立之后将保持有效,直到MappedByteBuffer对象被施以垃圾收集动作为止。NIO设计师们之所以做这样的决定是因为当关闭通道时破坏映射会引起安全问题,而解决该安全问题又会导致性能问题。
主要的方法

public abstract class MappedByteBuffer extends ByteBuffer { 
    // This is a partial API listing 
    public final MappedByteBuffer load( ) 
    public final boolean isLoaded( ) 
    public final MappedByteBuffer force( ) 
}

    load( )方法会加载整个文件以使它常驻内存。一个内存映射缓冲区会建立与某个文件的虚拟内存映射。此映射使得操作系统的底层虚拟内存子系统可以根据需要将文件中相应区块的数据读进内存。已经在内存中或通过验证的页会占用实际内存空间,并且在它们被读进RAM时会挤出最近较少使用的其他内存页。
在一个映射缓冲区上调用load( )方法会是一个代价高的操作,因为它会导致大量的页调入(page-in),具体数量取决于文件中被映射区域的实际大小。然而,load( )方法返回并不能保证文件就会完全常驻内存,这是由于请求页面调入(demand paging)是动态的。具体结果会因某些因素而有所差异,这些因素包括:操作系统、文件系统,可用Java虚拟机内存,最大Java虚拟机内存,垃圾收集器实现过程等等
    isLoaded( )方法来判断一个被映射的文件是否完全常驻内存了。如果该方法返回true值,那么很大概率是映射缓冲区的访问延迟很少或者根本没有延迟。不过,这也是不能保证的。同样地,返回false值并不一定意味着访问缓冲区将很慢或者该文件并未完全常驻内存。isLoaded( )方法的返回值只是一个暗示,由于垃圾收集的异步性质、底层操作系统以及运行系统的动态性等因素,想要在任意时刻准确判断全部映射页的状态是不可能的。
force()方法会强制将映射缓冲区上的更改应用到永久磁盘存储器上。MappedByteBuffer没有不更新文件元数据的选项——元数据总是会同时被更新的

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值