Simple G1GC tuning

Side notes

https://openjdk.java.net/jeps/304 ⇒ Garbage Collector Interface OpenJDK 10 https://openjdk.java.net/jeps/318 ⇒ Epsilon GC Experimental OpenJDK 11

https://openjdk.java.net/jeps/363 ⇒ Remove CMS OpenJDK 14

Default GC depends on "server class"

If your application is running with less than 2 cpus or less than 2gb of memory the JVM heuristics think the app is not running on a server, which makes the SerialGC the default GC, while this is unlikely to be an issue with apps that use less than 2GB of heap. It may well be an issue for apps that don’t use much CPU but require more memory. In this case it might be useful to toggle UseG1GC.

Corretto 11.0.7 JVM code source :

  • src/src/hotspot/share/runtime/os.cpp:1654-1699

    // This is the working definition of a server class machine:
    // >= 2 physical CPU's and >=2GB of memory, with some fuzz
    // because the graphics memory (?) sometimes masks physical memory.
    // If you want to change the definition of a server class machine
    // on some OS or platform, e.g., >=4GB on Windows platforms,
    // then you'll have to parameterize this method based on that state,
    // as was done for logical processors here, or replicate and
    // specialize this method for each platform.  (Or fix os to have
    // some inheritance structure and use subclassing.  Sigh.)
    // If you want some platform to always or never behave as a server
    // class machine, change the setting of AlwaysActAsServerClassMachine
    // and NeverActAsServerClassMachine in globals*.hpp.
    bool os::is_server_class_machine() {
  • src/src/hotspot/share/gc/shared/gcConfig.cpp:103-117

    This method is only used there in this release

    void GCConfig::select_gc_ergonomically() {
      if (os::is_server_class_machine()) {
    #if INCLUDE_G1GC
        FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);
    #elif INCLUDE_PARALLELGC
        FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
    #elif INCLUDE_SERIALGC
        FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
    #endif
      } else {
    #if INCLUDE_SERIALGC
        FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
    #endif
      }
    }

This heuristic probably predates containers and cgroups hype, and doesn’t look like it has been updated to reflect this trend.

Anyway it’s always possible to guide the JVM heuristics on this matter, using -XX:+AlwaysActAsServerClassMachine (which let’s the default GC be used), or by enabling a particular GC algorithm.

ZGC

https://openjdk.java.net/jeps/333 ⇒ Experiemental ZGC on OpenJDK 11 https://openjdk.java.net/jeps/351 ⇒ Uncommit on OpenJDK 13

https://openjdk.java.net/jeps/377 ⇒ ZGC is a product feature OpenJDK 15

https://openjdk.java.net/jeps/376 ⇒ Cocurrent Thread-Stack Processing on Open JDK 16

Table 1. GC concurrent components
Phase Serial Parallel G1 CMS ZGC

Marking

✖︎

✖︎

✔*

✔*

Compaction

✖︎

✖︎

✖︎

✖︎

Reference Processing

✖︎

✖︎

✖︎

✖︎

Relocation Set Selection

✖︎

✖︎

✖︎

✖︎

String table cleaning

✖︎

✖︎

✖︎

✖︎

JNI WeakRef Cleaning

✖︎

✖︎

✖︎

✖︎

JNI GlobalRef Cleaning

✖︎

✖︎

✖︎

✖︎

Class Unloading

✖︎

✖︎

✖︎

✖︎

Thread Stack Scanning

✖︎

✖︎

✖︎

✖︎

✖︎

  • * old gen only

  • ** not yet

colors unused 16 bits object address 44 bits, 16TB address space 64 bit object pointer
colored pointer

ZGC has load barrier (inserted by the JIT at strategic places) this barrier checks has a bad color, and fix the object reference.

Currently, ZGC time pause time increase with more threads (GC roots), because this phase is not concurrent. However, work has begun in JEP 376, which shows great progress so far ith sub-millisecond pauses.