【问题标题】:java.lang.OutOfMemoryError GC overhead limit exceeded vs Java heap space?java.lang.OutOfMemoryError GC 开销限制超过了 Java 堆空间?
【发布时间】:2023-04-04 04:55:01
【问题描述】:

java.lang.OutOfMemoryError: Java heap space 是什么意思 该消息意味着当应用程序需要的 Java 堆空间多于其正常运行的可用空间时。

java.lang.OutOfMemoryError: GC overhead limit exceeded 是什么意思 此消息意味着由于某种原因,垃圾收集器占用了过多的时间(默认情况下是进程所有 CPU 时间的 98%)并且在每次运行中恢复的内存非常少(默认情况下为堆的 2%)。这在内部也意味着当应用程序只需要比可用的更多 Java 堆空间来正常运行时。

所以我的问题是以上两种情况中的哪一种会被触发?

所以我的理解是什么时候会根据场景抛出特定的异常:-

假设我分配了 1GB 的堆大小。当前使用的堆内存为 970 MB。一个线程启动(JVM 不知道它会预先消耗多少内存)。 现在GC可以采取以下步骤之一

1) JVM 开始分配内存,然后在某个时间点耗尽 1GB 内存并抛出 java.lang.OutOfMemoryError: Java heap space

2) GC 提前运行并尝试释放一些内存,因为它知道当前正在使用的内存接近分配的 1 GB,堆。但它不能在每个空间中释放超过 2% 的空间 后续运行。然后它会抛出java.lang.OutOfMemoryError: GC overhead limit exceeded

就我的问题而言,我的理解是否正确?

【问题讨论】:

  • 是的..你的理解绝对正确。

标签: java garbage-collection heap-memory


【解决方案1】:

OutOfMemoryError: Java 堆空间

JVM 无法满足分配请求,即使在执行了所有最后的努力后也是如此。

OutOfMemoryError 超出 GC 开销限制

意味着 JVM 可能能够满足分配请求,但在最近它必须经常进行 GC,以至于花费在 GC 上的 CPU 时间量超过了 java 使用的总 CPU 时间的(可配置的)一部分过程。

JVM 会自行终止,而不是徘徊在半工作、效率极低的状态,随着时间的推移,这种状态可能只会变得更糟。

通常禁用 GC 开销 OOM 只会在几分钟后导致 Java 堆空间 OOM。

这基本上是一种快速失败的机制。

【讨论】:

  • JVM 不会在 OOM 上“自行终止”。只有当 OOM 导致最后一个非守护线程终止时,JVM 才会终止(通常的退出机制仍然适用)。
  • 对,我正在使用 -XX:OnOutOfMemoryError='kill -9 %p' 来实现这种效果,因为像 OOM 这样的随处抛出异常会使您的进程处于未定义状态
【解决方案2】:
java.lang.OutOfMemoryError: Java heap space

原因:无法在 Java 堆中分配对象。此错误不一定意味着内存泄漏。问题可以像配置问题一样简单,其中指定的堆大小(或默认大小,如果未指定)对于应用程序来说是不够的。

java.lang.OutOfMemoryError: GC Overhead limit exceeded

正如您所引用的,垃圾收集花费了过多的时间。这可能是您的应用程序中内存泄漏的副作用。 Old gen 可能由于泄漏而被完全填满,因此 GC 在垃圾回收周期中没有释放任何(或非常少)。

看看这个 oracle article 来解决不同类型的内存泄漏。

关于你的两个问题,我也认为你的理解是正确的,只是有区别。第二种情况下触发 GC 的事件不仅仅是新对象的创建。 Full GC 将在特定条件下触发。看看这个SE 问题。

【讨论】:

  • 人为减少 JBoss 服务器堆内存并部署应用程序会引发“超出 GC 开销限制”。没有泄漏,只是内存不足。
猜你喜欢
  • 1970-01-01
  • 2017-06-12
  • 2017-12-27
  • 2016-09-01
  • 1970-01-01
  • 2020-09-08
  • 2020-07-24
  • 1970-01-01
相关资源
最近更新 更多