【问题标题】:Java Refuses to Start - Could not reserve enough space for object heapJava 拒绝启动 - 无法为对象堆保留足够的空间
【发布时间】:2010-11-06 16:56:50
【问题描述】:

背景

我们有大约 20 个 linux 刀片库。有些运行 Suse,有些运行 Redhat。 ALL 共享 NAS 空间,包含以下 3 个文件夹:

  • /NAS/app/java - 指向 Java JDK 安装的符号链接。当前版本 1.5.0_10
  • /NAS/app/lib - 指向我们应用程序版本的符号链接。
  • /NAS/data - 写入输出的目录

我们所有的机器都有 2 个处理器(超线程),具有 4gb 的物理内存和 4gb 的交换空间。我们将每台机器在给定时间可以处理的“作业”数量限制为 6 个(这个数字可能需要更改,但这不属于当前问题,因此请暂时忽略它)。

我们的一些作业将最大堆大小设置为 512mb,而另一些作业将最大堆大小保留为 2048mb。同样,我们意识到如果在同一台机器上启动 6 个作业并将堆大小设置为 2048,我们可能会超出可用内存,但据我们所知,这还没有发生。

问题

有时,Job 会立即失败并显示以下消息:

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

我们过去常常将此归咎于同一台机器上同时运行的作业太多。该问题很少发生(可能每月一次),我们只需重新启动它,一切都会好起来的。

这个问题最近变得更糟了。我们所有请求最大堆大小为 2048m 的作业几乎每次都会立即失败,并且需要重新启动几次才能完成。

我们已经使用了个别机器并尝试手动执行它们,结果相同。

调试

事实证明,问题只存在于我们的 SuSE 盒子。它发生得更频繁的原因是因为我们一直在添加更多的机器,而新的机器是 SuSE。

SuSE 框中的“cat /proc/version”给我们:

Linux version 2.6.5-7.244-bigsmp (geeko@buildhost) (gcc version 3.3.3 (SuSE Linux)) #1 SMP Mon Dec 12 18:32:25 UTC 2005

RedHat 盒子上的“cat /proc/version”给我们:

Linux version 2.4.21-32.0.1.ELsmp (bhcompile@bugs.build.redhat.com) (gcc version 3.2.3 20030502 (Red Hat Linux 3.2.3-52)) #1 SMP Tue May 17 17:52:23 EDT 2005

'uname -a' 在两种类型的机器上为我们提供以下信息:

UTC 2005 i686 i686 i386 GNU/Linux

机器上没有正在运行的作业,也没有其他进程占用太多内存。当前运行的所有进程可能总共使用 100mb。

'top' 当前显示如下:

Mem:   4146528k total,  3536360k used,   610168k free,   132136k buffers
Swap:  4194288k total,        0k used,  4194288k free,  3283908k cached

'vmstat' 当前显示如下:

procs -----------memory---------- ---swap-- -----io---- --system-- ----cpu----
r  b   swpd   free   buff  cache   si   so    bi    bo   in    cs us sy id wa
0  0      0 610292 132136 3283908    0    0     0     2   26    15  0  0 100  0

如果我们使用以下命令行启动作业(最大堆为 1850mb),它会正常启动:

java/bin/java -Xmx1850M -cp helloworld.jar HelloWorld
Hello World

如果我们将最大堆大小增加到 1875mb,它会失败:

java/bin/java -Xmx1875M -cp helloworld.jar HelloWorld
Error occurred during initialization of VM
Could not reserve enough space for object heap
Could not create the Java virtual machine.

很明显,当前使用的内存是用于缓冲/缓存的,这就是为什么很少显示为“空闲”的原因。不清楚的是为什么会有一个神奇的 1850mb 行,任何更高的值都意味着 Java 无法启动。

任何解释将不胜感激。

【问题讨论】:

  • 为什么有 32b 刀片? :P
  • 嗨,Randyaa,您最终找出造成这种情况的原因了吗?当我尝试启动 WebLogic 服务器时,我遇到了同样的错误......谢谢
  • 很遗憾,没有,我们实施了一些技术来减少内存使用量,并且能够将最大使用量降低到 1gig 左右。对不起:(
  • +1 细节丰富。

标签: java linux memory jvm heap-memory


【解决方案1】:

您使用的是 32 位操作系统,因此您会看到总大小的限制。其他答案已经更详细地介绍了这一点,因此我将避免重复他们的信息。

我最近在我们的服务器上注意到的一个行为是,使用 -Xmx 指定最大堆大小而不使用 -Xms 指定最小堆大小会导致 Java 的服务器 VM 立即尝试分配所需的所有内存最大堆大小。当然,如果应用程序达到该堆大小,这就是您需要的内存量。但很有可能,您的应用一开始会使用相对较小的堆,可能在以后需要更大的堆。此外,指定最小堆大小将使您的应用从较小的堆开始,然后逐渐增大该堆。

所有这些都不会帮助您增加最大堆大小,但我认为它可能会有所帮助,所以...

【讨论】:

  • 我已经提到过,我认为这与我们的 32 位操作系统无关。 SuSE 和 RedHat 机器都是 32 位的,它们都没有问题。至于您设置最小值的建议,我试过了,但对我没有任何帮助:(。
【解决方案2】:

正如其他回复中所建议的,问题是由虚拟地址空间耗尽引起的。一个 32 位的 linux 用户空间程序通常限制为 3GB 的 AS;剩余的 1GB 由内核使用(理由:由于顶部 1GB 是内核固定映射,因此在提供系统调用时无需触及页表)。

但是,RHEL 内核实现了所谓的 4GB/4GB 拆分,其中完整的 4GB AS 可用于用户空间进程,但运行时开销很小(内核位于单独的 4GB 虚拟 AS 中)

【讨论】:

    【解决方案3】:

    运行 32 位操作系统是错误的;您一定要尽早升级。

    我不知道 Java 是否要求其堆位于单个连续块中,但如果需要,在 32 位机器上要求 1.8G 的堆听起来是一项艰巨的任务。您假设在 JVM 启动时有一块地址空间,几乎一半是空闲的。

    根据当时加载的其他库,可能没有。库可以在他们喜欢的任何地方分配内存,因此它可以充分分割您的地址空间,以至于 1.8G 无法在一个块中使用。

    无论如何,Linux 32 位上最多只有大约 3G 的地址空间可用。库和 JVM 本身使用一些来开始。

    【讨论】:

    • 如果可以的话我会换的。这不取决于我。我需要解决手头的问题,这就是 Redhat 机器允许我们使用 2500+ 以及 SuSE 机器将我们限制为 1850 的原因。
    【解决方案4】:

    对于 32 位服务器,似乎存在无法克服的 JVM 限制(除非您找到不施加 2GB 或更少限制的特殊 32 位 JVM)。

    服务器端的这个线程有更多细节,包括几个人在 32 位架构上测试了各种 JVM。 IBM 的 JVM 似乎允许多出 100 MB,但这并不能真正满足您的需求。

    http://www.theserverside.com/discussions/thread.tss?thread_id=26347

    “真正的”解决方案是使用带有 64 位 JVM 的 64 位服务器来获得每个进程大于 2GB 的堆。但是,重要的是还要考虑使用 64 位 JVM 增加地址大小(不仅仅是可寻址空间)的影响。使用少于 4GB 内存的处理可能会对性能和内存产生影响。

    深思:这些工作真的需要 2GB 内存吗?有什么办法可以将作业修改为在 1.8GB 内运行,这样这个限制就没有问题了?

    【讨论】:

    • 我真的不认为这是一个 32 位的问题。两台机器都运行 32 位操作系统,它们各自有不同的限制。 RedHat 盒子限制在 2500+MB 左右,SuSE 盒子在 1850Mb 左右。
    • 至于更改系统或“真的”需要 2GB... 我们计划进行一些更改以减少内存印记,但是;在这一点上是的,它确实需要。
    【解决方案5】:

    ulimit 最大内存大小和虚拟内存设置为无限制?

    【讨论】:

    • ulimit 在两者上都是无限的。我在哪里检查虚拟内存限制?
    • 将 ulimit 与 -a 开关一起使用。 ulimit -a
    【解决方案6】:

    我写了两个应用程序,一个中等大小,另一个相当小。我会开火 中型(在 linux,centos 上),没有任何 args,(java 服务器),它会 运行得很好。但是当我用“java客户端”启动较小的应用程序时,它会告诉 我它无法保留足够的空间,也不会运行。我进行了实验,并使用了 10m 的 -Xms 和 -Xmx,它们都可以毫无怨言地运行......去看看!

    【讨论】:

      【解决方案7】:

      这可能偏离了正轨,但有两件事情浮现在脑海中。以下两项均假设您运行的是 32 位版本的 Linux。

      linux 有一个进程大小限制,似乎记得在 CentOS 上大约是 2.5gb,并且在内核中进行了配置(即重新完成更改)。一旦您将所有 JVM 代码 + Permgen 空间和所有其余 JVM 库相加,您的进程可能会遇到这种情况。

      第二件事是我遇到的事情,您可能会用完地址空间,我知道这听起来很奇怪。使用 1.5Gb 堆运行 Glassfish 时出现问题,当它尝试编译一个 JSP 我的分叉 javac 时它会失败,因为即使盒子中有 12GB 内存,操作系统也无法为新创建的进程分配足够的地址空间。这里可能会发生类似的事情。

      恐怕只有以上两个的解决办法,哪里升级到64位内核。

      希望这有一些用处。

      【讨论】:

      • 正如我已经提到的,如果 SuSE 盒子和 RedHat 盒子都有这个问题,我会同意你的看法。它们都是 32 位操作系统,它们有不同的限制。 Redhat 似乎在 2500+ MB 左右,而 SuSE 盒子似乎在 1850 MB 左右。
      • 不同的发行版可能有不同的进程大小限制默认值。它们也有不同的内核版本。
      【解决方案8】:

      您需要考虑升级您的操作系统和 Java。 Java 5.0 已停产,但如果您无法更新到 Java 6,您可以使用最新的补丁级别 22!

      32 位 Windows 限制为 ~ 1.3 GB,因此您可以将最大值设置为 1.8。注意:这是连续内存的问题,当您的系统运行时,它的内存空间可能会变得碎片化,所以我不会惊讶您有这个问题。

      64 位操作系统没有这个问题,因为它有更多的虚拟空间,您甚至不必升级到 64 位版本的 java 即可利用这一点。

      顺便说一句,根据我的经验,32 位 Java 5.0 可以比 64 位 Java 5.0 更快。直到多年后,Java 6 update 10 才更快地用于 64 位。

      【讨论】:

        【解决方案9】:

        我把一台机器的内存从2GB升级到4GB,马上就开始报错:

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

        问题在于 ulimit,我将可寻址空间设置为 1GB。 将其增加到 2GB 解决了这个问题。

        -Xms 和 -Xmx 无效。

        看起来 java 试图获取与可用内存成比例的内存,如果不能,则失败。

        【讨论】:

          【解决方案10】:

          要执行的步骤 .... 解决 初始化虚拟机时出错 无法为对象堆保留足够的空间 无法创建 Java 虚拟机。

          第 1 步:减少之前使用的内存。 java -Xms128m -Xmx512m -cp simple.jar

          第 2 步:从主板上取下 RAM 一段时间,然后将其插入并重新启动 * 可能会释放阻塞堆区域内存.. java -Xms512m -Xmx1024m -cp simple.jar

          希望它现在运行良好... :-)

          【讨论】:

            【解决方案11】:

            我最近遇到了这个问题。我有 3 个以 1024m 或 1280m 堆大小开头的 java 应用程序。 Java 正在查看 swap 中的可用空间,如果没有足够的可用内存,则 jvm 退出。

            为了解决这个问题,我不得不结束几个分配了大量虚拟内存的程序。

            我在带有 64 位 jvm 的 x86-64 linux 上运行。

            【讨论】:

              【解决方案12】:

              使用的 JVM 是什么? 我知道 BEA JRockit 的最大堆大小不超过 1850mB。它不会失败,但会警告用户它不会使用超过 1850mB。

              我不知道为什么会有这样的限制,但我知道它存在于 BEA JRockit。

              最好的问候。

              【讨论】:

              • 我们只是使用 Sun 的 JVM。 java version "1.5.0_10" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_10-b03) Java HotSpot(TM) Server VM (build 1.5.0_10-b03, mixed mode)
              • 我刚刚在 Windows XP 上使用 Sun 客户端 VM 进行了测试。以上 -Xmx1640M 我得到了和你一样的错误: 初始化 VM 时发生错误 无法为对象堆保留足够的空间 无法创建 Java 虚拟机。我测试的程序是HelloWorld。该限制由 JVM 固定。
              • Oracle JRockit 与 Sun 和 IBM 的 JVM:s 不同,它可以使用非连续堆。这意味着您可以在 Windows 上获得近 3 GB,但不确定在 Linux 上可以获得多少。有关更多信息,请参阅此博客; blogs.oracle.com/jrockit/2008/09/…
              【解决方案13】:

              鉴于其他建议均无效(包括我自己建议的许多事情),为了帮助进一步排除故障,您能否尝试运行:

              sysctl -a
              

              在 SuSE 和 RedHat 机器上查看是否有任何差异?我猜这两个发行版的默认配置是不同的。

              【讨论】:

              • /sbin/sysctl 在您的路径中吗?实际上,只需尝试运行 /sbin/sysctl -a。
              【解决方案14】:

              我正在使用 SOA 环境,将 setSOADomainENV.cmd 中的 Xmx 从 1024 减少到 768 解决了这个问题。

              REM set DEFAULT_MEM_ARGS=-Xms512m -Xmx1024m
              set DEFAULT_MEM_ARGS=-Xms512m -Xmx768m
              

              【讨论】:

              • 欢迎来到 SO。你确定你回答的问题正确吗?
              【解决方案15】:

              在 Windows 中,我解决了这个问题,直接编辑文件 /bin/cassandra.bat,更改“Xms”和“Xmx”JVM_OPTS 参数的值。您可以尝试编辑 /bin/cassandra 文件。在这个文件中,我看到一个注释变量 JVM_OPTS,尝试取消注释并编辑它。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2021-05-16
                • 2023-03-13
                • 2012-12-11
                • 2014-02-28
                • 2013-08-05
                相关资源
                最近更新 更多