IO知识Java篇(5) -内存映射缓存、直接缓存

问题引入: IO操作的过程中有一个重要的问题,就是如何将内核缓冲区中DMA传进来的数据传输给用户空间?通常有两种方法:一种是进行数据拷贝的方; 而另一种是直接将内核内存映射给用户程序。写的情形也可以类比.本文将介绍有关内存映射缓存、直接缓存的相关知识,分析第二种方式对应的java api.

 

一 内存映射文件及MappedByteBuffer

(1)通过FileChannel.map(MapMode mode, long position, long size)建立MappedByteBuffer与磁盘文件的映射,映射机制是基于虚拟内存的;虚拟内存管理中,虚拟存储分为硬盘虚拟区与系统内核内存虚拟区,虚拟存储管理器以页为单位将磁盘的文件区的文件映射到虚拟页的数据结构,通过页中断及页替换在硬盘与系统之间进行数据调入调出;而MappedByteBuffer已读入的数据或写出的数据是直接放入对应系统内核内存虚拟区的

 

(2)MapMode有三种:

READ_ONLY只读: 试图修改得到的缓冲区将导致抛出 ReadOnlyBufferException. 

READ_WRITE读/写: 对得到的缓冲区的更改最终将传播到文件;该更改对映射到同一文件的其他程序不一定是可见的,要使用MappedByteBuffer.force方法及时将更改的页内容刷新到文件,但是文件的内容何时刷新到其他程序对同一文件的缓冲区是不确定的.

MapMode.PRIVATE 专用: 对得到的缓冲区的更改不会传播到文件,并且该更改对映射到同一文件的其他程序也不是可见的;相反,会创建缓冲区已修改部分的专用副本,这个副本也是以页为单位的,被修改的内容所在的页将会被拷备,  外部对拷备页位置内容的更改不影响专用buffer,但外部对非拷备页对应内容的修改将影响这个专用buffer

 

(3)MappedByteBuffer是ByteBuffer的子类,使用方法与ByteBuffer相似

 

(4)很多内存映射文件的细节从根本上是取决于底层操作系统的,因此是未指定的。当所请求的区域没有完全包含在此通道的文件中时,此方法的行为是未指定的。未指定是否将此程序或另一个程序对底层文件的内容或大小所进行的更改传播到缓冲区。未指定将对缓冲区的更改传播到文件的频率。

         将文件映射到内存使得用户区与内核区之间缓冲区的数据的拷备的IO过程省略了,但对于大多数操作系统而言,与通过普通的 read 和 write 方法读取或写入数千字节的数据相比,将文件映射到内存中开销更大。从性能的观点来看,通常将相对较大的文件映射到内存中才是值得的。 

 

二 直接缓存

        DirectByteBuffer是MappedByteBuffer的子类,通过静态的ByteBuffer.allocateDirect(int capacity)方法获取指定缓冲区大小的DirectByteBuffer对象. 下面介绍其与MappedByteBuffer的区别:

        MappedByteBuffer对象对应的缓冲区中的数据页的管理取决于操作系统虚拟存储管理机制,而DirectByteBuffer可看作是在OS中给JVM进程分配一块指定大小的固定的内存块.也就是说,在内存充足的情况下,MappedByteBuffer可能会导致操作系统将整个大文件加载进内存,可能伴随着许多内存页的换进换出.而DirectByteBuffer对应内核缓冲区的大小是固定的,对应在内存中的页的数量也是固定的,不会造成内存使用的大起大落.

        当内存充足时,并且文件大小与剩余内存空间大小差不多时,那么可以使用MappedByteBuffer,让操作系统直接把整个大文件加载进来,在这处情形下的IO速度是非常之快的.

        当读写一个超级大的文件并且内存不充足(其他程序运行对内存的需求大),为避免操作系统频繁地对内存页进行换进换出,那么可以使用DirectByteBuffer指定固定大小的缓冲区来使用,以减轻OS对内存管理的负荷.

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
内存映射文件是一种将文件映射到进程的虚拟地址空间中的技术,它可以让程序直接访问磁盘上的文件,就好像访问内存一样。当我们需要读取或写入大量数据时,使用内存映射文件可以提高IO性能,因为它避免了频繁的磁盘IO操作和缓存的使用。 内存映射文件的基本思路是将一个文件或一部分文件映射到进程的虚拟地址空间中,这个虚拟地址空间就成为了文件的一个镜像。在进程中,我们可以像访问内存一样访问这个虚拟地址空间,对这个虚拟地址空间的读写操作会自动映射到磁盘上的文件中。当我们修改了这个虚拟地址空间的数据时,内核会自动将这些修改同步到磁盘上的文件中。 在Linux中,可以使用mmap()系统调用来实现内存映射文件。mmap()函数可以将一段虚拟地址空间映射到一个文件描述符所表示的文件中。mmap()函数的原型如下: ``` void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); ``` 其中,addr是期望映射的虚拟地址空间的起始地址,如果addr为NULL,则由系统自动分配一个地址;length是映射的长度;prot是内存保护标志,用于指定映射区域的访问权限;flags是控制映射区域的各种属性;fd是文件描述符;offset是文件中的偏移量。 使用内存映射文件时需要注意以下几点: 1. 内存映射文件需要占用进程的虚拟地址空间,因此需要注意虚拟地址空间的大小; 2. 内存映射文件需要和文件描述符一起使用,因此需要注意文件描述符的打开和关闭; 3. 内存映射文件修改的数据需要及时同步到磁盘上,因此需要注意数据同步的方式和时机; 4. 内存映射文件的使用需要考虑数据的安全性,避免出现数据损坏或数据丢失的情况。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值