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% 時,會拋出這個異常。

微信搜索“我的編程喵”關注公眾號,每日一刷,輕松提升技術,斬獲各種offer:

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM