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

Stella981
• 阅读 557

默认情况下,并不是等堆内存耗尽,才会报 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:

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

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
3个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解
Opencv中Mat矩阵相乘——点乘、dot、mul运算详解2016年09月02日00:00:36 \牧野(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fme.csdn.net%2Fdcrmg) 阅读数:59593
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Stella981 Stella981
3年前
Git提交本地以及远程仓库
项目方法Gc75n047Fm3109gDDPJ2006.07.14101007MpkyG专访抖音绽放公会「分享」运营经验(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fhzcya.com%2Fdywh%2F320.html)00azE2
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这