Tomcat报错"java.lang.OutOfMemoryError: Java heap space",但是dump文件中的堆大小小于-Xmx。

5
我们的Tomcat服务器抛出了“java.lang.OutOfMemoryError: Java heap space”错误,但转储文件中的堆大小仅为1.7GB,而-Xmx为4GB。 我不确定发生了什么,请你帮助我解决这个问题。 环境: Redhat tomcat6 jdk6
3个回答

2
XmxSIZE可以比Java核心转储更大,因为在尝试分配大型对象时会发生OutOfMemory!我们的应用程序使用-Xmx1000m和670 MiB转储,在用户上传300 MiB附件时由于OutOfMemory而崩溃。我们在“显示线程”跟踪中的VisualVM中发现了这一点,其中System.arrayCopy被调用。来自本地堆栈帧变量的引用指向300 MiB字节数组。现在我们限制附件大小并保护我们的应用程序免受未来崩溃的影响。

1

Salah的回答在很多方面都是错误的,我认为这是直接有害的。

首先,JVM不会在死亡之前触发Stop The World GC并清理堆内存以避免OutOfMemoryError。造成OOM的原因是GC未能在OOM之前清理内存,通常是在数十次和数百次运行期间。

其次,推荐的比率实际上并非JVM供应商推荐的。最佳比率严重依赖于应用程序,因此如果不知道您在做什么,最好保持默认设置而不是遵循此建议。


是的,我不明白为什么JVM会抛出OOM异常,而GC可以将堆清理到1.7GB。 - CQLI

0

首先,您需要查看以下内存参数,这可能无法防止OutOfMemoryError,但您应该了解它们:

-Xmx2048m -> this param to set the max memory that the JVM can allocate
-Xms1024m -> the init memory that JVM will allocate on the start up
-XX:MaxPermSize=512M -> this for the max Permanent Generation memory

另外,您可能还想检查这些参数,这些参数将加速Young空间中的GC活动,从而使收集效果更好。

-XX:MaxNewSize=  -> this need to be 40% from your Xmx value
-XX:NewSize=614m -> this need to be 40% from your Xmx value

同时,你可以告诉你的JVM使用哪种类型的GC(我认为这种类型已经在最新的JVM版本中启用):

-XX:+UseConcMarkSweepGC

第二

当发生OutOfMemoryError时,JVM将触发Stop World GC,因此它将收集您的对象和未引用的对象,这就是为什么堆大小小于您的-Xmx值。

通常在这种情况下,如果您使用其中一种分析工具分析此堆,则会清楚地找到填充内存的大型对象,这将使您进入代码并很容易修复它。


为什么NewSize应该是40%,您能提供一些您所参考的参考文档吗? - Vipin
我建议大家阅读这个这个。谢谢。 - Salah
@Salah,你在第一条评论中提供的链接说“-XX:NewSize = 2m:新一代的默认大小(以字节为单位)[5.0及更高版本:64位VM比例增加30%; x86:1m; x86,5.0及更早版本:640k]”,我无法理解这个描述。你能否详细说明一下? - Vipin
谢谢大家。我仍然困惑,如果在堆转储之前触发了完整的GC,并且它将堆大小从4G减少到1.7G,为什么JVM会在这个安全堆大小抛出OOM。 - CQLI
@Vipin,这些是此参数“2MB”的默认值,然后它说明它们在最新的“虚拟机”中将值增加30%,因此几乎为640k - Salah
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接