内存映射文件:优点和缺点



我需要在同一台机器(两个不同的jvm)上运行的两个Java应用程序之间共享数据。我确定要共享的数据很大(大约7 GB)。应用程序必须非常快地访问数据,因为它们必须以非常高的速度回答传入的查询。我不希望每个应用程序都保留一个数据副本。

我看到一个选项是使用内存映射文件。应用程序A从某处(假设是数据库)获取数据并将其存储在文件中。然后应用程序B可以使用java.nio访问这些文件。我不知道内存映射文件是如何工作的,我只知道数据存储在一个文件中,并且这个文件(或它的一部分)被映射到内存的一个区域(虚拟内存?)因此,这两个应用程序可以读写内存中的数据,并且自动(我猜?)将更改提交到文件中。我也不知道是否有一个文件完全映射到内存的最大大小。

我的第一个问题是,在这种情况下,两个应用程序共享数据的不同可能性是什么(我的意思是考虑到数据量非常大,对这些数据的访问必须非常快)?我确定这个问题与内存映射I/O无关,它只是想知道解决相同问题的其他方法。

我的第二个问题是使用内存映射文件的利弊是什么?

谢谢

我的第一个问题是两个应用程序共享数据的不同可能性是什么?

正如S.Lott指出的,有很多机制:

  • os级消息队列
  • os级POSIX共享内存段(在进程死亡后持续存在)
  • os级内存映射(可以是匿名的或文件支持的)
  • os级匿名管道(单向)
  • os级命名管道(单向)
  • os级套接字(双向)—AF_UNIXAF_INETAF_INET6
  • 操作系统级共享全局内存——适用于多线程程序
  • 将数据存储到文件
  • 应用程序级消息队列
  • 应用级黑板式元空间
  • 应用程序级键/值存储
  • 应用程序级远程过程调用框架——很多都可用
  • 应用级web框架

我的第二个问题是使用内存映射文件的利弊是什么?

优点:

  • 非常快——根据您访问数据的方式,可以使用潜在的零复制机制直接对数据进行操作,而不会造成速度损失。必须注意以一致的方式更新对象
  • 应该是非常可移植的——在Unix系统上可以使用大约25年(给或左右),显然Windows也有机制。

缺点:

  • 单系统共享。如果您希望将应用程序分布在多台机器上,那么共享内存并不是一个很好的选择。分布式共享内存系统是可用的,但在我看来,它们似乎是错误的接口。
  • 即使在单个系统上,如果内存位于单个NUMA节点上,但需要来自多个节点的处理器访问,那么与给每个节点自己的内存段相比,节点间请求可能会显著减慢处理速度。
  • 你不能仅仅存储指针——所有的东西都必须存储为到基址的偏移量,因为内存可能在不同的进程中映射到不同的位置。我不知道这对Java对象意味着什么,尽管可能有些聪明的人尽了最大努力使它对Java程序员透明。如果您没有使用他们提供的机制,那么您可能必须自己完成工作。(在Java中没有实际的指针,也许这不是很麻烦。)
  • 始终如一地更新对象被证明是非常困难的。在消息传递系统中传递不可变对象通常会导致程序具有更少的并发错误。(Erlang中的并发编程感觉非常自然和直接。命令式语言中的并发编程倾向于引入大量新的并发控制(信号量、互斥锁、自旋锁、监视器)。

内存映射文件听起来很令人头疼。一个简单且不易出错的选择是使用具有集群感知缓存的共享数据库。这样一来,只有写操作下到数据库,读操作可以从缓存中读取。

作为如何在hibernate中这样做的示例,请参见http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html#performance-cache

最新更新