Java:如何在32位JVM中使用超过4GB内存的堆

5
我们有一个产品,目前运行在32位1.6 JRE上。我们使用Berkeley DB,它占用了4GB地址空间中约2.5GB的RAM。这使得我们在JVM地址空间中只剩下大约750MB的内存。
目前,我们的设置已经出现了OutOfMemory问题。我们希望将JVM堆大小增加到1.5GB,同时仍保留Berkeley DB的2.5GB空间。是否有办法在32位JVM中访问超过4GB RAM/堆?我考虑了以下解决方案: 1)使用更好的GC的JVM--这将给我较小的结果--可以获得大约50-100MB的工作内存; 2)类似memcached或“out of process ehcache”的东西--这会为我提供尽可能多的硬件资源,但需要IPC/序列化的开销。
有没有其他解决方案可以增加应用程序的可寻址内存?
该解决方案应该适用于运行sparc的solaris 10系统。
*更新:由于使用了本地共享库,所以我们目前无法切换到64位JVM,即使操作系统是64位*
谢谢!

1
操作系统是Solaris 64位,具有大量的GB RAM。只有Java进程需要更多的RAM/堆空间。 - anjanb
anjanb,你能说出BerkeleyDB的准确版本吗?BerkeleyDB分配了多少内存? - osgx
3个回答

5

有没有其他解决方案来增加应用程序的可寻址内存?

  1. 将单个应用程序拆分为多个进程,使用非共享内存(不是线程;而是进程)。第一个进程可以运行数据库,第二个进程可以运行项目的其他部分。您可以使用RMI或共享内存或套接字在进程之间通信。
  2. 降低保留给操作系统的内存。例如,在x86-32 PAE上允许操作系统保留小于4 GB虚拟地址空间的一部分。 (例如,“4GB / 4Gb分裂”,在Oracle Linux上受支持)
  3. 将一些数据放到磁盘上。磁盘可以是RAM磁盘以获得更好的速度;或者它可以是真实的磁盘,操作系统将使用“页面缓存”加速对文件的访问。
此外,每个真正的SPARC(不是古老的SuperSparc或贫穷的LION)都是64位的。因此,切换到64位操作系统可能更容易。我不知道Solaris的情况,但在Linux中,可以在64位操作系统之上运行32位应用程序。并且64位操作系统将允许您运行64位JVM。
更新:Solaris中有RAM磁盘http://wikis.sun.com/display/BigAdmin/Talking+about+RAM+disks+in+the+Solaris+OS,我认为您应该尝试将其用于存储数据库(或临时数据库文件)。与第一种情况不同,这里没有额外的序列化/IPC; 只有额外的读/写或mmap/munmap。但是Ramdisk比SSD快几个数量级,比HDD快3到4个数量级。

1
你能将本地库移动到单独的进程中吗?你尝试在64位操作系统上运行32位JVM了吗(这可以帮助避免2/2或3/1 GB分割)? - osgx
1
如果他已经获得了3.2GB的地址空间,那么他已经在使用你所提到的第二点,无论他使用的是什么操作系统(Windows也有类似的功能)。虽然我不明白为什么64位操作系统在这种情况下不会给他整个32位地址空间 - 这很奇怪(至少Windows应该在这种情况下使整个4GB可用)。 - Voo
因此,如果您没有更多可用的虚拟内存,您将无法为堆获得更多GB,并且您唯一能做的就是将一些数据移动到其他地方:其他进程或Ram磁盘或类似AWE的东西(这类似于32位Windows进程中大于4 GB的HighMem)。 - osgx
是的,我们正在使用一个巨大的“页面缓存”,使得数据库大部分在内存中而不是慢速磁盘查找中。 - anjanb
VLM就像Linux下的AWE:http://download.oracle.com/docs/cd/B28359_01/server.111/b32009/appi_vlm.htm - osgx
显示剩余6条评论

3

32位程序不能处理超过4GB的内存地址,因为它们没有足够的位数来表示更多的内存。

2^32 = 4 294 967 296

升级到64位的JRE是最好的选择。


由于使用本地共享库,尽管操作系统是64位的,但我们现在无法切换到64位JVM。 - anjanb
在这种情况下,您可能需要将应用程序拆分为多个进程,正如osg建议的那样。 - StriplingWarrior

3

我建议您在32位JVM中运行32位共享本机库,并在64位JVM中运行其他所有内容。您可以让64位JVM调用32位JVM来执行它所需的任何操作。我假设大部分数据/内存需求可以移动到64位JVM。


这是我们需要进行实验并观察是否对系统预期的吞吐量有意义的事情。 - anjanb
你应该能够在同一台机器上的两个进程之间实现500 MB/s到3000 MB/s的吞吐量(取决于你的硬件)。 - Peter Lawrey
你能否建议一种最佳方法,让一个64位Java应用程序与32位Java应用程序进行通信。我知道通常的Unix/Linux IPC机制,但这些机制在64位Java和32位Java情况下哪种效果最好? - anjanb
1
JVM 的位数不应该成为问题。我会使用普通的 Socket,使用阻塞 IO 或 NIO 可能是最简单的方法。您可以使用 IO 中的 DataOutput/InputStream 或 NIO 中的 ByteBuffers。您可以通过单个 TCP 连接发送数百万条消息,往返延迟低于 20 微秒。 - Peter Lawrey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接