Java堆空间 – -Xmx如何正常工作?

我在我的应用程序中遇到了臭名昭着的OutOfMemoryException ,而不是简单地增加可用堆空间的数量,我试图查看问题所在,以防万一,我的应用程序出现了某种泄漏。

我添加了JVM参数-XX:+ HeapDumpOnOutOfMemoryError ,当遇到OutOfMemory错误时会创建堆转储。 然后我分析了使用不同的分析工具生成的转储文件。 然后我开始使用-Xmx参数并观察模式。

令我困惑的是以下内容。 为什么在分析转储时我发现所有对象的总大小远小于我使用-Xmx参数设置的总大小? 例如,假设我将-Xmx设置为’2048m’。 当我分析转储文件时,我在堆上发现了总共400Mb的对象。 我期待找到2GB。 我错过了什么吗?

重新阅读您的错误消息 – 它可能会告诉您哪种类型的内存耗尽了。 我猜这是PermGen的空间。 Permgen用于类定义(以及其他内容)。 您可以通过-XX调整PermGen的空间:MaxPermSize PermGen不是堆的一部分,因此不包含在堆转储中。

有关查看PermGen的更多信息,请参阅此答案 。

如果这不是问题,那么尝试将初始堆大小(-Xms)设置为与最大值相同。 这样做意味着堆不会增长,这应该让您更容易理解正在发生的事情。

我建议使用jvisualvm(JDK的一部分)来查看程序运行时的内存利用率。

我的猜测是,由于现代GC将堆分区为独立的内存区域(年轻/终端/永久代),因此永久生成空间完全填满内存错误就足够了。 您可以使用各种JVM命令行选项配置不同生成空间的比率。

这是一篇关于使用5.0 Java [tm]虚拟机调优垃圾收集的好文章(我找不到更新的虚拟机,但我认为基础知识仍适用于较新的虚拟机)。