【问题标题】:32-bit JVM maximum memory size on 64-bit Windows not as large as expected64 位 Windows 上的 32 位 JVM 最大内存大小没有预期的那么大
【发布时间】:2026-01-13 06:55:02
【问题描述】:

我在内存映射 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 位,因为我得到的实际地址空间远小于预测的能力。

标签: java jvm memory-mapped-files mappedbytebuffer


【解决方案1】:

您的地址空间很可能是碎片化的,可用的连续地址空间不超过 550MB。如果您需要对大文件进行内存映射,则需要能够在必要时将它们分段映射。

【讨论】:

  • 感谢您的回答。我不确定 JVM 究竟是如何分配内存的,但根据 SO 上的几篇文章,JVM 分配了一个最大大小的大的连续内存区域。这是否意味着 Java 程序可以保证有一个连续的地址空间区域,该区域的大小大约是 JVM 堆的大小?也就是说,如果JVM能被初始化,大概会有足够的连续地址空间?
  • @Fenwick 这取决于平台。例如,在某些平台上,如果该地址可用,库会加载到固定地址,以改善页面共享并最大限度地减少重定位。这可能意味着当进程最终开始时,内存会严重碎片化。尽可能迁移到 64 位。
  • @Fenwick 如果 JVM 可以初始化,并且它分配了 1GB 堆,那么有 1GB 的连续未使用空间。但是这 1GB 不再被使用,因为堆正在使用它。
最近更新 更多