【问题标题】:JVM YoungGen 0%, Perm Gen 99%, OldGen FullJVM YoungGen 0%,Perm Gen 99%,OldGen Full
【发布时间】:2016-09-10 21:54:01
【问题描述】:

我有一个 JEE 应用程序最近开始出现 CPU 使用高峰(例如 40 核服务器上 100% 的 27 核),并且应用程序不可用的时间越来越长。这与以下帖子中描述的问题非常相似,包括弹跳应用程序服务器会使问题消失,直到它在几个小时后再次出现:

Old Gen heap is full and the Eden and Survivor are low and almost empty

当应用程序遇到这些“冻结”时,我获取了一些核心转储输出,我看到了以下 JVM GC 输出:

PSYoungGen total 11221504K, used 2435K
eden space 9238528K, 0% used
from space 19829796K, 0% used
to space 1970176K, 0% used
ParOldGen total 39613440K, used 39276477K
object space 39613440K, 99% used
PSPermGen total 254976K, used 115497K
object space 254976K, 45% used

根据引用的帖子和上述输出,我想我理解“冻结”是由在 ParOldGen 空间上运行的垃圾收集器(徒劳?)驱动的。我缺少的部分:

  1. 为什么 PermGen 空间的使用率保持在 45%。也就是说,ParOldGen 中约 39GB 的内容最终会转变为 PSPermGen 吗?

  2. 几乎空无一人的 PSYoungGen 空间有何意义?这是否意味着应用程序在稳定状态下没有创建任何/许多新对象实例?

上面的帖子还描述了为 ParOldGen“提供更多空间”的选项,但我不清楚这是否意味着通过 -Xmx 增加总堆大小,或者是否有明确的 JVM GC 参数。我看到NewRatio 参数控制年轻代相对于老一代的大小。 PSYoungGen 本质上是空的这一事实是否意味着它太大了,我应该使用较小的NewRatio 值?

提前感谢您的帮助。

【问题讨论】:

  • 老一代的东西没有被提升到永久空间,你可能在永久空间的某个地方有泄漏,你的应用程序是否动态创建了很多类?
  • 感谢您的评论。我现在明白 permgen 空间不是堆的一部分(每个 stackoverflow.com/questions/2129044/… )。该应用程序确实动态创建了很多类。看来我们要么有内存泄漏,要么应用程序的内存需求超过了当前的 -Xmx 值。
  • 您动态创建了很多类或对象?如果是类,那么你的 permgen 会满,如果是对象,那么 oldgen。
  • 那些类定义进入 PermGen 空间,如果你创建很多它们,你可能会达到 MaxPermSize 并且最终会出现缓慢和 OOM,再次查看数据,你的 permgen 没有调查麻烦区,这是你的老一代
  • OldGen 大约 40Gb 的堆空间 + YoungGen 大约 10Gb 的堆空间,这意味着您正在使用 50Gb 堆运行。这对我来说很重要。你能提供一些细节,为什么你需要这么多?无论如何,我认为首先你需要生成一个堆转储并使用 MAT 或其他任何东西对其进行分析。了解哪些对象正在占用您的堆,您是否真的需要在堆中使用它们,如果不需要,请了解为什么它们不是 GC-ed。

标签: java garbage-collection jvm heap-memory


【解决方案1】:

ParOldGen 中大约 39GB 的内容最终会过渡到 PSPermGen 吗?

Java 7 中的 PermGen(在 Java 8 中被元空间取代)用于保存代码。从堆传递到 PermGen 的唯一东西是字节码,所以除非你正在生成或加载类,否则没有任何东西从一个传递到另一个。它们是不同的空间。

几乎空无一人的 PSYoungGen 空间有何意义?

full GC 后年轻代为空。一旦你的老一代开始填满,Full GC 很常见。

这是否意味着应用程序在稳定状态下没有创建任何/许多新对象实例?

这更有可能意味着它最近经过了 Full GC-ed。

描述了为 ParOldGen “提供更多空间”的选项,但我不清楚这是否意味着通过 -Xmx 增加总堆大小,或者是否有明确的 JVM GC 参数。

增加最大堆可以给你更多的空间,但我会先检查

  • 您没有内存泄漏。
  • 您不能将大量数据移出堆,例如数据库或本机内存。

PSYoungGen 本质上是空的这一事实是否意味着它太大,我应该使用较小的 NewRatio 值?

这可能会帮助您为老一代提供更多空间,但它可能只会在内存耗尽之前给您更多时间。

【讨论】:

    【解决方案2】:

    为什么 PermGen 空间的使用率保持在 45%。也就是说,ParOldGen 中大约 39GB 的内容最终会过渡到 PSPermGen 吗?

    没有。 OldGen & PermGen 空间不能共享。 PSPermGen 主要包含由 PermGen 空间中的类加载器加载的类。 ParOldGen 包含用于长寿命对象的堆内存。

    在 JDK 1.8 中,PermGen 已被 Metaspace 取代。有关详细信息,请参阅此article

    有关详细信息,请参阅以下 SE 问题:

    Java heap terminology: young, old and permanent generations?

    几乎空无一人的 PSYoungGen 空间有何意义?这是否意味着应用程序不会在稳定状态下创建任何/许多新对象实例?

    @Peter Lawrey 已正确回答。在 Full GC 之后,YoungGen 几乎是空的 => 您没有从应用程序中的短期对象中积累垃圾

    上面的帖子还描述了为 ParOldGen“提供更多空间”的选项,但我不清楚这是否意味着通过 -Xmx 增加总堆大小,或者是否有明确的 JVM GC 参数。

    您的旧代已满意味着您的应用程序正在从长期存在的对象中保留堆。

    现在您必须使用 visualvmMAT 等分析工具检查应用程序中可能存在的内存泄漏(如果有)

    如果您没有内存泄漏,您可以使用-Xmx 增加堆大小。

    PSYoungGen 本质上是空的这一事实是否意味着它太大,我应该使用较小的 NewRatio 值?

    由于您使用较大的堆,我建议您使用 G1GC 算法。如果您使用 G1GC 算法,请不要自定义默认值,因为 G1GC 算法可以更好地管理堆。

    查看有关G1GC 开关(Complete List of G1 GC Switches 部分)、Use Cases 文章和相关 SE 问题的 Oracle 文章:

    Java 7 (JDK 7) garbage collection and documentation on G1

    【讨论】:

      猜你喜欢
      • 2013-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-04
      • 2021-04-21
      • 2021-07-21
      • 1970-01-01
      • 2013-03-10
      相关资源
      最近更新 更多