6

我正在为 Java 堆空间设置而苦苦挣扎。无论操作系统版本如何,Windows 上的默认 Java 都是 32 位客户端(这是 Oracle 向所有用户推荐的)。默认情况下,它似乎将最大堆大小设置为 256 MB,这对我来说太小了。

我使用自定义启动器来启动应用程序。我希望它在具有大量 RAM 的计算机上使用更多内存,并默认使用-Xmx512m在具有较少 RAM 的计算机上。据我所知,唯一的方法是静态-Xmx设置(必须在启动时设置)。

我有一个拥有 8 GB RAM、64 位 Windows 和 32 位 Java 7 的用户。JVM 可见的最大内存为 4G(由查询返回OperatingSystemMXBean)。我明白为什么,没问题。

由于某种原因,我的应用程序无法为该用户启动-Xmx1300m,即使他有 2.3G 可用内存。他关闭了一些应用程序(拥有 5G 可用内存),但仍然无法启动。报告给我的错误是:

error occured during init of vm
could not reserve enough space for object heap

这是怎么回事?难道 32 位 JVM 只能处理“第一个”4G 内存,并且必须在前 4 GB 内存中有 1300M 块可用?

除了要求每个人都安装 64 位 Java(这是不可能接受的)之外,我该如何解决这个问题?

编辑:如果重要的话,它是一个胖的 Swing 客户端,而不是一个小程序。

4

5 回答 5

2

这不是内存问题,而是地址空间问题。

在理论上可由 32 位进程寻址的 4 GB (2^32) 上,必须考虑操作系统内核需要该地址空间的一部分(显然进程无法触及)这一事实。

当你使用 Java 时,java进程本身的地址空间被进一步分割,在堆、permgen、本机资源、JVM 本身等之间。

您使用的是 64 位操作系统。运行 64 位 JVM。您的字节码(即您所有的 jars)将运行相同。没有理由使用 32 位 JVM!

于 2013-06-24T16:09:44.883 回答
2

为什么它不起作用?

正如其他人所提到的,这个特定用户的计算机很可能在 32 位地址空间中没有足够大的连续空闲内存块供 JVM 使用。最大 32 位堆空间取决于系统(请注意,操作系统和确切的 JVM 版本都会有所不同),但在 Windows 上通常约为 1100-1600 MB。例如,在我的 64 位 Windows 7 系统上,这些是我安装的特定 32 位 JVM 版本的最大 -Xmx 大小:

  • Java 7:在 1100m 和 1200m 之间
  • Java 6:1400m 到 1500m 之间
  • Java 5:1500m 到 1600m 之间

分配给进程的剩余内存由操作系统(或模拟器,在 64 位主机上的 32 位进程的情况下)、JVM 本身以及 JVM 使用的其他结构使用。

推荐的解决方案:将 64 位 JVM 与您的应用程序捆绑在一起

如果您无法让客户端安装 64 位 JVM,请将其与您的应用程序捆绑在一起。64 位地址空间将有一个大于 1300 MB 可用的连续内存块,即使不一定有足够大的连续物理内存块可用。

如果您的软件是一个独立的应用程序,那么捆绑 JVM 是小菜一碟。如果启动器是一个小程序,那么在启动应用程序之前,您可能必须让您的小程序检查已知位置的 64 位 JVM(并在必要时下载它)。

不要忘记依赖关系

如果您的应用程序使用 32 位本机库,请确保您也可以获得这些本机库的 64 位版本。

如果您无法捆绑 JVM 或具有 32 位本机依赖项怎么办?

您确实没有理由不能将 JVM 与您的应用程序捆绑在一起,但您可能有一些 32 位本机依赖项尚未移植到 64 位——在这种情况下,这无关紧要您是否捆绑了 JVM,因为您仍然坚持使用 32 位。java -Xmx####m -version在这种情况下,您可以通过重复执行和解析输出(####当然,Xmx 值在哪里) ,让您的启动器执行二进制搜索以确定最大堆大小。找到最大 Xmx 后,您可以使用该值启动程序。(注意:稍微安全一点的选择是简单地尝试运行程序并检查堆空间错误,在每次尝试启动程序失败后减少 Xmx。)

如果您收到如下错误消息之一,则需要使用较小的 Xmx 值:

爪哇 7:

Error occurred during initialization of VM
Could not reserve enough space for object heap
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

爪哇 6:

Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

爪哇 5:

Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

但是如果你得到类似下面的东西,你知道你已经找到了最大值,或者你可以尝试一个更大的 Xmx 值:

Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Client VM (build 23.21-b01, mixed mode)
于 2013-06-24T19:30:55.303 回答
1

我同意前面的答案。只是一些额外的评论。是的,32 位理论上可以访问 4GB,但是在 Windows 中,上半部分为操作系统保留,下半部分为所有应用程序保留。由于 Windows 将 Java 视为“用户”程序,而不是操作系统的一部分,因此您能做的最好的事情就是 2GB。在实践中,它比这要少得多。1.2GB 听起来差不多。

但是,在 32 位模式下运行时,我实际上建议降低到 1024M。如果您绝对最大化堆空间,您可能会遇到更严重的问题,即“本机内存”用完。而且,如果您在此之前从未体验过它,那将是一种真正的享受——因为不是获得良好的 Java 堆栈跟踪,而是整个 JVM 立即崩溃。

我同意其他所有人的观点,即您需要硬着头皮增强您的应用程序以支持 64 位 JVM。在我的例子中,我们有一个服务包装器,所以我们需要重新分配两个 JVM,然后是一个 32 位服务包装器和一个 64 位服务包装器。然后,用户可以根据需要注册 32 位或 64 位版本。

于 2013-06-24T16:34:00.957 回答
1

Windows XP 被限制为 1.2 - 1.4 GB 的连续内存。即使您有 64 位 JVM,32 位仿真的工作方式与 Windows XP 的兼容性相同,即也有相同的限制。

如果要使用更多内存,请运行 64 位 JVM。除非您有 32 位 DLL,否则没有理由不这样做。

于 2013-06-24T18:34:01.543 回答
0

我处理的应用程序需要尽可能多的内存。通过反复试验,我发现在 Windows 下,我可以可靠地分配给 32 位 JVM 的最大容量约为 1200 MB。它略有不同,但我从来不知道它会低于这个值。在运行 OpenJVM 的 Linux 下,我有时可以分配 1300MB。这个限制有很多原因,但从我所读到的主要问题之一是阻止 JVM 获取比这更大的堆是要求堆是一个连续的内存块。

当您在 64 位机器上运行 64 位操作系统时,我强烈建议您切换到 64 位 JVM。然后,您可以分配基本上无限量的内存。然而,我的实验表明,超过 10GB 的内存是一个严重的收益递减情况,因为 JVM 似乎没有很好地使用它并且性能受到影响。我相信 Java 8 会更好地管理大量内存。

于 2013-06-24T16:18:05.957 回答