64位Windows上的32位JVM最大内存大小没有预期的那么大

问题描述:

我一直有一个艰难的时间内存映射550MB文件。我知道32位JVM可以分配1.4G左右的最大内存大小,所以我需要按部分映射大文件。但是,这是一个550MB的文件,但我仍然无法将它全部映射到内存中。我能做的最好的是大约333MB的缓冲区大小。64位Windows上的32位JVM最大内存大小没有预期的那么大

下面是我的测试代码:

void testMap() throws IOException{ 
    long buffer = 500000000; // CAUSES ERROR. best I can do is 350000000 
    RandomAccessFile srcFile = new RandomAccessFile("550MBFile", "r"); 
    ByteBuffer srcbb = srcFile.getChannel().map(MapMode.READ_ONLY, 0, buffer); 
} 

,误差如下:

Exception in thread "main" java.io.IOException: Map failed at sun.nio.ch.FileChannelImpl.map(Unknown Source) at TestSpliter.testMap(TestSpliter.java:22) at TestSpliter.main(TestSpliter.java:14) Caused by: java.lang.OutOfMemoryError: Map failed ...

JVM参数:-Xms1024m

任何人都可以解释为什么我只能用300MB 1.4GB?谢谢。

请注意,这与32位JVM的最大堆大小有关,这不是重复问题。

+1

为什么不能使用64位JVM? – immibis 2014-11-09 01:19:41

+1

@immibis:可能是“因为IT这么说”...... – 2014-11-09 01:20:21

+0

@immibis只需设置一台新的Windows 8.1 PC并测试一些旧代码即可。 Java.com默认为Win8提供32位下载,所以如果我的应用程序可以支持32位JVM,我认为它会很好。其实我认为这里的问题并不是真正的32位,因为我得到的实际地址空间远小于预测的能力。 – Fenwick 2014-11-09 01:32:25

很可能,您的地址空间是分散的,连续地址空间不超过550MB。如果您需要映射大文件的内存映射,则需要能够将它们分段映射(如果需要)。

+0

感谢您的回答。我不确定JVM究竟是如何分配内存的,但根据SO上的一些帖子,JVM会分配一个最大大小的连续内存区域。这是否意味着Java程序保证有一个与JVM堆大小大小相近的连续地址空间区域?换句话说,如果JVM可以被初始化,那么可能会有足够的连续地址空间? – Fenwick 2014-11-09 02:03:24

+0

@Fenwick它取决于平台。例如,在某些平台上,如果该地址可用,则将库装载到固定地址,以改善页面共享并最小化重定位。这可能意味着只有当流程最终开始时,内存才会非常分散。如果可能的话,迁移到64位。 – 2014-11-09 02:32:04

+2

@Fenwick如果JVM可以初始化,并且它分配1GB堆,那么*有* 1GB的连续未使用空间。但是这个1GB不会再被使用,因为这个堆正在使用它。 – immibis 2014-11-09 04:31:05