64 位 Windows 上的 32 位 JVM 最大内存大小没有预期的那么大
Posted
技术标签:
【中文标题】64 位 Windows 上的 32 位 JVM 最大内存大小没有预期的那么大【英文标题】:32-bit JVM maximum memory size on 64-bit Windows not as large as expected 【发布时间】:2014-11-09 01:18:22 【问题描述】:我在内存映射 550MB 文件时遇到了困难。我了解 32 位 JVM 最多可以分配 1.4G 左右的内存大小,所以我需要将一个大文件分部分映射。但是,这是一个 550MB 的文件,但我仍然无法将其全部映射到内存中。我能做的最好的事情是缓冲区大小约为 333MB。
下面是我的测试代码:
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
谁能解释为什么我只能使用 1.4GB 中的 300MB?谢谢。
请注意,这不是与那些询问 32 位 JVM 的最大堆大小的问题重复的问题。
【问题讨论】:
为什么不能使用 64 位 JVM? @immibis:可能“因为 IT 这么说”... @immibis 刚刚设置了一台新的 Windows 8.1 PC 并测试了一些旧代码。 Java.com 默认为 Win8 提供 32 位下载,所以我认为如果我的应用程序可以支持 32 位 JVM,那就太好了。实际上,我认为这里的问题实际上并不在于 32 位,因为我得到的实际地址空间远小于预测的能力。 【参考方案1】:您的地址空间很可能是碎片化的,可用的连续地址空间不超过 550MB。如果您需要对大文件进行内存映射,则需要能够在必要时将它们分段映射。
【讨论】:
感谢您的回答。我不确定 JVM 究竟是如何分配内存的,但根据 SO 上的几篇文章,JVM 分配了一个最大大小的大的连续内存区域。这是否意味着 Java 程序可以保证有一个连续的地址空间区域,该区域的大小大约是 JVM 堆的大小?也就是说,如果JVM能被初始化,大概会有足够的连续地址空间? @Fenwick 这取决于平台。例如,在某些平台上,如果该地址可用,库会加载到固定地址,以改善页面共享并最大限度地减少重定位。这可能意味着当进程最终开始时,内存会严重碎片化。尽可能迁移到 64 位。 @Fenwick 如果 JVM 可以初始化,并且它分配了 1GB 堆,那么有 1GB 的连续未使用空间。但是这 1GB 不再被使用,因为堆正在使用它。以上是关于64 位 Windows 上的 32 位 JVM 最大内存大小没有预期的那么大的主要内容,如果未能解决你的问题,请参考以下文章
可以通过参数“-d32”强制 64 位 JVM 使用 32 位模式吗?
32位JVM和64位JVM的最大堆内存分别是多数?32位和64位的JVM,int类型变量的长度是多数?