Saturday, November 8, 2014

HotSpot: GC Worker Threads Used in CMS, Parallel, and G1 GC

As discussed in [1], the Java HotSpot virtual machine includes five garbage collectors (or GC):
  • Serial Collector
  • Parallel Collector (or throughput collector)
  • Parallel Compacting Collector
  • Concurrent Mark-Sweep (CMS) Collector
  • Generation First (G1) Garbage Collector
Also, in [2], we have shown how to find the default HotSpot JVM values.  Some VM options are set from command line and some are set by GC's ergonomics.  However, all VM options are printed when you execute:
  • -XX:+PrintFlagsFinal
Using G1 GC as an example, it uses SurvivorRatio, but not InitialSurvivorRatio, MinSurvivorRatio, or TargetSurvivorRatio.  In this article, we will show you one way to tell which VM option is used by which GC.

GC Threads


In [3], we have discussed the difference between Parallel Collectors and Concurrent Collectors.

Parallel collectors require stop-the-world pause for the whole duration of major collection phases (mark or sweep), but employ all available cores to compress pause time. Parallel collectors usually have better throughput, but they are not a good fit for pause critical applications. 
Concurrent collectors try to do most work concurrently (though they also do it in parallel on multi-core systems), stopping the application only for short duration. Note that the concurrent collection algorithm in JRockit is fairly different from both HotSpot's concurrent collectors (CMS and G1).

There are three kinds of GC threads utilized in HotSpot for CMS, Parallel, and G1 garbage collectors:
  • ParallelGCThreads
  • ConcGCThreads 
  • G1ConcRefinementThreads
When you use PrintFlagsFinal to print out all JVM flags for CMS, Parallel or G1 GC.  The results are as follows:

CMS
    uintx ParallelGCThreads           = 23     {product}
    uintx ConcGCThreads               = 6      {product}
    uintx G1ConcRefinementThreads     = 0      {product}
Parallel GC     uintx ParallelGCThreads           = 23     {product}     uintx ConcGCThreads               = 0      {product}     uintx G1ConcRefinementThreads     = 0      {product}
G1 GC
    uintx ParallelGCThreads           = 23     {product}
    uintx ConcGCThreads               = 6      {product}
    uintx G1ConcRefinementThreads     = 23     {product}

Based on JDK-8047976,[4] it says that GC's normally don't update flags they do not use.  That's why we see "0" in some of the printouts.  To summarize, here are the GC worker threads used in CMS, Parallel, and G1 garbage collectors:

Garbage Collector
Worker Threads Used
CMS
ParallelGCThreads
ConcGCThreads
Parallel
ParallelGCThreads
G1
ParallelGCThreads
ConcGCThreads
G1ConcRefinementThreads

Note that the above description is valid for the following JVM version or later ones:
java version "1.8.0_40-ea"
Java(TM) SE Runtime Environment (build 1.8.0_40-ea-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b16, mixed mode)
Because JDK-8047976 bug,[4] the behavior is different if you use earlier versions.

References

  1. HotSpot VM Performance Tuning Tips (Xml and More)
  2. What Are the Default HotSpot JVM Values? (Xml and More)
  3. JRockit: Parallel vs Concurrent Collectors (Xml and More)
  4. Ergonomics for GC thread counts should update the flags
  5. Tuning that was great in old JRockit versions might not be so good anymore
    • Trying to bring over each and every tuning option from a JR configuration to an HS one is probably a bad idea.
    • Even when moving between major versions of the same JVM, we usually recommend going back to the default (just pick a collector and heap size) and then redoing any tuning work from scratch (if even necessary).

No comments: