/ GC overhead limit exceeded: Understand your JVM ~ Java EE Support Patterns

1.20.2012

GC overhead limit exceeded: Understand your JVM

For JVM related problems and tuning, I always recommend application support individuals to improve their basic JVM skills. The OpenJDK HotSpot implementation (c++ code) allows you to understand at a lower level the JVM business logic and memory conditions triggering errors such as GC overhead limit exceeded.

This article will attempt to dissect the JVM business logic so you can better understand this severe Java memory condition.

java.lang.OutOfMemoryError: GC overhead limit exceeded

Before going any deeper into this problem and HotSpot implementation, I first recommend that you review my first 2 articles on the subjects as they will provide you an overview of this problem along with common patterns and recommendations:


HotSpot implementation – GC overhead limit exceeded logic

Find below a JVM c++ code snippet showing you both the pseudo code and implementation of the JVM logic leading to the GC overhead limit exceeded error message.

The primary criteria’s and conditions leading to GC overhead limit exceeded are as per below:

1)     Full GC triggered / observed
2)     GC cost e.g. everage time is higher than default limit. This means the time spent in GC is way too high
3)     The amount of memory available is smaller than limit e.g. this means your JVM is very close to full depletion (OldGen + YoungGen)
4)     The GC overhead limit count is reached e.g. typically 5 iterations limit is the default

Now please find below a snippet of the OpenJDK HotSpot implementation (c++). You can download the full OpenSource HotSpot implementation at:

  bool print_gc_overhead_limit_would_be_exceeded = false;
  if (is_full_gc) {
    if (gc_cost() > gc_cost_limit &&
      free_in_old_gen < (size_t) mem_free_old_limit &&
      free_in_eden < (size_t) mem_free_eden_limit) {
      // Collections, on average, are taking too much time, and
      //      gc_cost() > gc_cost_limit
      // we have too little space available after a full gc.
      //      total_free_limit < mem_free_limit
      // where
      //   total_free_limit is the free space available in
      //     both generations
      //   total_mem is the total space available for allocation
      //     in both generations (survivor spaces are not included
      //     just as they are not included in eden_limit).
      //   mem_free_limit is a fraction of total_mem judged to be an
      //     acceptable amount that is still unused.
      // The heap can ask for the value of this variable when deciding
      // whether to thrown an OutOfMemory error.
      // Note that the gc time limit test only works for the collections
      // of the young gen + tenured gen and not for collections of the
      // permanent gen.  That is because the calculation of the space
      // freed by the collection is the free space in the young gen +
      // tenured gen.
      // At this point the GC overhead limit is being exceeded.
      inc_gc_overhead_limit_count();
      if (UseGCOverheadLimit) {
        if (gc_overhead_limit_count() >=
            AdaptiveSizePolicyGCTimeLimitThreshold){
          // All conditions have been met for throwing an out-of-memory
          set_gc_overhead_limit_exceeded(true);
          // Avoid consecutive OOM due to the gc time limit by resetting
          // the counter.
          reset_gc_overhead_limit_count();
        } else {
          // The required consecutive collections which exceed the
          // GC time limit may or may not have been reached. We
          // are approaching that condition and so as not to
          // throw an out-of-memory before all SoftRef's have been
          // cleared, set _should_clear_all_soft_refs in CollectorPolicy.
          // The clearing will be done on the next GC.
          bool near_limit = gc_overhead_limit_near();
          if (near_limit) {
            collector_policy->set_should_clear_all_soft_refs(true);
            if (PrintGCDetails && Verbose) {
              gclog_or_tty->print_cr("  Nearing GC overhead limit, "
                "will be clearing all SoftReference");
            }
          }
        }
      }
      // Set this even when the overhead limit will not
      // cause an out-of-memory.  Diagnostic message indicating
      // that the overhead limit is being exceeded is sometimes
      // printed.
      print_gc_overhead_limit_would_be_exceeded = true;

    } else {
      // Did not exceed overhead limits
      reset_gc_overhead_limit_count();
    }
  }


Please feel free to post any comment or ask me any question.

2 comments:

Thanks for sharing this valuable information P-H. Indeed knowing little more detail of JVM helps to troubleshoot problem more effectively.-XX:+UseGCOverheadLimit can be used to specify the limit I guess. by the way what is your take to solve this problem.

Javin
2 Solution of OutOfMemoryError in Java

Thanks Javin for your comments and article sharing,

You can also have a look at this post as it provide problem patterns and troubleshooting / solution approaches for this problem:

http://javaeesupportpatterns.blogspot.ca/2011/08/gc-overhead-limit-exceeded-problem-and.html

Regards,
P-H

Post a Comment