JVM 报 GC Overhead limit exceeded 是什么意思?

简介: JVM 报 GC Overhead limit exceeded 是什么意思?

默认情况下,并不是等堆内存耗尽,才会报 OutOfMemoryError,而是如果 JVM 觉得 GC 效率不高,也会报这个错误。

那么怎么评价 GC 效率不高呢?来看下源码: 呢?来看下源码gcOverheadChecker.cpp

void GCOverheadChecker::check_gc_overhead_limit(GCOverheadTester* time_overhead,
                                                GCOverheadTester* space_overhead,
                                                bool is_full_gc,
                                                GCCause::Cause gc_cause,
                                                SoftRefPolicy* soft_ref_policy) {
  // 忽略显式gc命令,比如System.gc(),或者通过JVMTI命令的gc,或者通过jcmd命令的gc
  if (GCCause::is_user_requested_gc(gc_cause) ||
      GCCause::is_serviceability_requested_gc(gc_cause)) {
    return;
  }
  bool print_gc_overhead_limit_would_be_exceeded = false;
  if (is_full_gc) {
    //如果gc时间过长,并且gc回收的空间还是不多
    //gc时间占用98%以上为gc时间过长,可以通过 -XX:GCTimeLimit= 配置,参考gc_globals.hpp: GCTimeLimit
    //回收空间小于2%为gc回收空间不多,可以通过  -XX:GCHeapFreeLimit= 配置,参考gc_globals.hpp: GCHeapFreeLimit
    if (time_overhead->is_exceeded() && space_overhead->is_exceeded()) {
      _gc_overhead_limit_count++;
      //如果UseGCOverheadLimit这个状态位为开启
      //默认情况下,是开启的,可以通过启动参数-XX:-UseGCOverheadLimit关闭,参考:gc_globals.hpp: UseGCOverheadLimit
      if (UseGCOverheadLimit) {
        //如果超过规定次数,这个次数默认不可配置,必须开启develop编译jdk才能配置,参考gc_globals.hpp: GCOverheadLimitThreshold
        if (_gc_overhead_limit_count >= GCOverheadLimitThreshold){
          //设置状态位,准备抛出OOM
          set_gc_overhead_limit_exceeded(true);
          //清空计数
          reset_gc_overhead_limit_count();
        } else {
          //如果还没到达次数,但是也快到达的时候,清空所有的软引用
          bool near_limit = gc_overhead_limit_near();
          if (near_limit) {
            soft_ref_policy->set_should_clear_all_soft_refs(true);
            log_trace(gc, ergo)("Nearing GC overhead limit, will be clearing all SoftReference");
          }
        }
      }
      //需要打印日志,提示GC效率不高
      print_gc_overhead_limit_would_be_exceeded = true;
    } else {
      // Did not exceed overhead limits
      reset_gc_overhead_limit_count();
    }
  }
  if (UseGCOverheadLimit) {
    if (gc_overhead_limit_exceeded()) {
      log_trace(gc, ergo)("GC is exceeding overhead limit of " UINTX_FORMAT "%%", GCTimeLimit);
      reset_gc_overhead_limit_count();
    } else if (print_gc_overhead_limit_would_be_exceeded) {
      assert(_gc_overhead_limit_count > 0, "Should not be printing");
      log_trace(gc, ergo)("GC would exceed overhead limit of " UINTX_FORMAT "%% %d consecutive time(s)",
                          GCTimeLimit, _gc_overhead_limit_count);
    }
  }
}

默认配置:gc_globals.hpp

product(bool, UseGCOverheadLimit, true,                                   \
          "Use policy to limit of proportion of time spent in GC "          \
          "before an OutOfMemory error is thrown")                          \
                                                                            \
product(uintx, GCTimeLimit, 98,                                           \
      "Limit of the proportion of time spent in GC before "             \
      "an OutOfMemoryError is thrown (used with GCHeapFreeLimit)")      \
      range(0, 100)                                                     \
                                                                        \
product(uintx, GCHeapFreeLimit, 2,                                        \
      "Minimum percentage of free space after a full GC before an "     \
      "OutOfMemoryError is thrown (used with GCTimeLimit)")             \
      range(0, 100)                                                     \
                                                                        \
develop(uintx, GCOverheadLimitThreshold, 5,                               \
      "Number of consecutive collections before gc time limit fires")   \
      range(1, max_uintx)

可以总结出:默认情况下,启用了 UseGCOverheadLimit,连续 5 次,碰到 GC 时间占比超过 98%,GC 回收的内存不足 2% 时,会抛出这个异常。

相关文章
|
3月前
|
算法 Java
太狠了!阿里技术专家撰写的电子版JVM&G1 GC实战,颠覆了传统认知
JVM是Java语言可以跨平台、保持高发展的根本,没有了 JVM, Java语言将失去运行环境。针对 Java 程序的性能优化一定不可能避免针对JVM 的调优,随着 JVM 的不断发展,我们的应对措施也在不断地跟随、变化,内存的使用逐渐变得越来越复杂。所有高级语言都需要垃圾回收机制的保护,所以 GC 就是这么重要。
|
3月前
|
算法 Java
JVM GC和常见垃圾回收算法
JVM GC和常见垃圾回收算法
48 0
|
3月前
|
缓存 监控 算法
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
jvm性能调优实战 - 39一次大促导致的内存泄漏和Full GC优化
68 0
|
4月前
|
存储 缓存 算法
JVM(四):GC垃圾回收算法
JVM(四):GC垃圾回收算法
|
3月前
|
架构师 Java
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
jvm性能调优实战 - 35电商APP后台系统如何对Full GC进行深度优化
52 0
|
3月前
|
存储 监控 算法
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
垃圾回收器、垃圾回收算法、空间分配担保、JVM调优、GC回收对象的过程
|
3月前
|
存储 分布式计算 前端开发
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
jvm性能调优实战 - 26一个每秒10万并发的系统如何频繁发生Young GC的
61 0
|
2月前
|
算法 Java
深入理解JVM - 解读GC日志
深入理解JVM - 解读GC日志
50 0
|
3月前
|
算法 Java
JVM GC 垃圾回收
【1月更文挑战第3天】JVM GC 垃圾回收
|
3月前
|
存储 算法 Java
JVM GC 算法
对于JVM的垃圾收集(GC),这是一个作为Java开发者必须了解的内容,那么,我们需要去了解哪些内容呢,其实,GC主要是解决下面的三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 回答了这三个问题,也就对于GC算法的原理有了最基本的了解。