49

背景

我们有一个大约 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,我们可能会超出可用内存,但据我们所知,这还没有发生。

问题

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

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。

“顶部”当前显示以下内容:

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

如果我们使用以下命令行(Max Heap of 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 无法启动。

任何解释将不胜感激。

4

15 回答 15

21

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

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

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

于 2009-06-29T17:03:41.713 回答
15

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

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

于 2009-11-06T15:23:40.247 回答
8

运行 32 位操作系统是错误的;您绝对应该尽早升级。

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

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

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

于 2009-06-30T06:43:17.750 回答
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 内运行,所以这个限制不是问题吗?

于 2009-06-29T16:44:59.343 回答
3

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

于 2009-06-29T19:19:00.920 回答
3

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

于 2012-10-05T05:20:28.327 回答
2

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

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

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

恐怕只有以上两种的解决方案才能升级到 64 位内核。

希望这有点用。

于 2009-06-29T16:40:20.157 回答
2

您需要考虑升级您的操作系统和 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 位。

于 2010-05-13T21:24:09.073 回答
2

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

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

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

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

于 2011-11-24T09:57:57.750 回答
2

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

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

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

于 2013-02-12T21:15:19.420 回答
2

我将一台机器的内存从 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试图按照可用内存的比例获取内存,如果不能,则会失败。

于 2010-12-22T20:46:20.953 回答
1

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

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

此致。

于 2009-06-29T14:07:40.630 回答
1

鉴于其他建议都不起作用(包括我自己建议的许多事情),为了帮助进一步排除故障,您可以尝试运行:

sysctl -a

在SuSE和RedHat这两个机器上看看有没有区别?我猜这两个发行版之间的默认配置是不同的,这导致了这种情况。

于 2009-06-29T19:28:35.580 回答
1

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

REM set DEFAULT_MEM_ARGS=-Xms512m -Xmx1024m
set DEFAULT_MEM_ARGS=-Xms512m -Xmx768m
于 2012-03-27T04:54:12.470 回答
-3

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

于 2011-09-11T11:52:46.827 回答