【JAVA之共享内存】

共享内存对应应用开发的意义

对熟知UNIX系统应用开发的程序员来说,IPC(InterProcess Communication)机制是非常熟悉的,IPC基本包括共享内存、信号灯操作、消息队列、信号处理等部分,是开发应用中非常重要的必不可少的工具。其中共享内存IPC机制的关键,对于数据共享、系统快速查询、动态配置、减少资源耗费等均有独到的优点。

对应UNIX系统来说,共享内存分为一般共享内存和映像文件共享内存两种,而对应Windows,实际上只有映像文件共享内存一种。所以JAVA应用中,也是只能创建映像文件共享内存。

在JAVA语言中,基本上没有提及共享内存这个概念,但是,在某一些应用中,共享内存确实非常有用,例如采用JAVA语言的分布式应用系统中,存在着大量的分布式共享对象,很多时候需要查询这些对象的状态,以查看系统是否运行正常或者了解这些对象的目前的一些统计数据和状态。如果采用网络通信的方式,显然会增加应用的额外负担,也增加了一些不必要的应用编程。而如果采用共享内存的方式,则可以直接通过共享内存查看对象的状态数据和统计数据,从而减少了一些不必要的麻烦。

共享内存的使用有如下几个特点:

1)可以被多个进程打开访问; 

2)读写操作的进程在执行读写操作时其他进程不能进行写操作; 

3)多个进程可以交替对某一共享内存执行写操作; 

4)一个进程执行了内存的写操作后,不影响其他进程对该内存的访问。同时其他进程对更新后的内存具有可见性; 

5)在进程执行写操作时如果异常退出,对其他进程写操作禁止应自动解除; 

6)相对共享文件,数据访问的方便性和效率。

另外,共享内存的使用上有如下情况:

1)独占的写操作,相应有独占的写操作等待队列。独占的写操作本身不会发生数据的一致性问题。

2)共享的写操作,相应有共享的写操作等待队列。共享的写操作则要注意防止发生数据的一致性问题。 

3)独占的读操作,相应有共享的读操作等待队列。

4)共享的读操作,相应有共享的读操作等待队列。

在jdk1.4中提供的类MappedByteBuffer为我们实现共享内存提供了较好的方法。该缓冲区实际上是一个磁盘文件的内存映像。二者的变化将保持同步,即内存数据发生变化会立刻反映到磁盘文件中,这样会有效的保证共享内存的实现。

将共享内存和磁盘文件建立联系的是文件通道类:FileChannel。该类的加入是JDK为了统一对外部设备(文件、网络接口等)的访问方法,并且加强了多线程对同一文件进行存取的安全性。例如读写操作统一成read和write。这里只是用它来建立共享内存用,它建立了共享内存和磁盘文件之间的一个通道。

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

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

java中共享内存的应用:

1.永久对象的配置

2.共享数据的查询

存映射文件的优缺点

可能内存映射IO的主要优势是性能,内存映射文件比通过普通的IO来访问文件要快,这对于繁忙的电子交易系统来说非常重要。内存映射IO另外一个优势是能够加载普通方式无法访问的大文件,实验表明内存映射IO在大文件处理中表现得更好;但缺点是有增加页面错误(page fault)的可能,因为操作系统仅仅加载一部分文件到内存中,如果被请求的页面不在内存中那就会导致一个页面错误。大多数主流操作系统如Windows, Unix, Solaris和其他类Unix的操作系统都支持内存映射IO,在64位架构下,你几乎可以将任何文件映射到内存中并直接使用Java访问。另外一个优势是这些文件能够共享,在进程间提供共享内存,而且比普通的基于loopback接口的Socket要快10倍。

总结

下面快速总结一下Java内存映射文件和IO

1)Java语言通过java.nio包支持内存映射文件和IO。

2)内存映射文件用于对性能要求高的系统中,如繁忙的电子交易系统

3)使用内存映射IO你可以将文件的一部分加载到内存中

4)如果被请求的页面不在内存中,内存映射文件会导致页面错误

5)将一个文件区间映射到内存中的能力取决于内存的可寻址范围。在32位机器中,不能超过4GB,即2^32比特。

6)Java中的内存映射文件比流IO要快(译注:对于大文件而言是对的,小文件则未必)

7)用于加载文件的内存在Java的堆内存之外,存在于共享内存中,允许两个不同进程访问文件。顺便说一下,这依赖于你用的是direct还是non-direct字节缓存。

8) 读写内存映射文件是操作系统来负责的,因此,即使你的Java程序在写入内存后就挂掉了,只要操作系统工作正常,数据就会写入磁盘。

9)Direct字节缓存比non-direct字节缓存性能要好

10 )不要经常调用MappedByteBuffer.force()方法,这个方法强制操作系统将内存中的内容写入硬盘,所以如果你在每次写内存映射文件后都调用force()方法,你就不能真正从内存映射文件中获益,而是跟disk IO差不多。

11)如果电源故障或者主机瘫痪,有可能内存映射文件还没有写入磁盘,意味着可能会丢失一些关键数据。

12)MappedByteBuffer和文件映射在缓存被GC之前都是有效的。sun.misc.Cleaner可能是清除内存映射文件的唯一选择。

猜你喜欢

转载自gaojingsong.iteye.com/blog/2368486