"-XX:ParallelGCThreads" - # of Threads

This section describes how to use the '-XX:ParallelGCThreads' JVM option to control the number threads to be used by the Parallel Collector.

In the previous tutorial, we learned that the Parallel collector did use 2 parallel threads to perform both Young and Full GCs.

The next question is then how the Parallel collector determines the number of threads to use and any options to control it.

By search Java documentation, I found this description: "On a machine with N hardware threads where N is greater than 8, the parallel collector uses a fixed fraction of N as the number of garbage collector threads. The fraction is approximately 5/8 for large values of N. On selected platforms, the fraction drops to 5/16. At values of N below 8, the number used is N.

But the output from the previous tutorial contradicts what's said in Java documentation. The Parallel collector used 2 parallel threads, however my virtualized Windows 10 computer has 4 cores and 8 logical processors. The Parallel collector should use 8 threads.

If you want control the number of parallel treads explicitly, you can use the "-XX:ParallelGCThreads=n" JVM option. In the example below, I ran the test program with 4 parallel threads:

herong> java -Xms40m -Xmx80m -XX:+UseParallelGC \
   -Xlog:gc=debug,gc+heap=info,gc+task+time=debug \
   -XX:ParallelGCThreads=4 GarbageCollection

[info][gc] Using Parallel
[info][gc,heap] GC(0) PSYoungGen: 10240K->1504K(11776K)
[info][gc,heap] GC(0) ParOldGen: 0K->1843K(27648K)
[info][gc] GC(0) Pause Young (Allocation Failure) 10M->3M(38M) 4.245ms
[debug][gc,task,time] GC(0) VM-Thread 861668 869434 870054
[debug][gc,task,time] GC(0) GC-Thread 0 entries: 3
[debug][gc,task,time] GC(0)     [ noop task 861773 861773 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861803 867733 ]
[debug][gc,task,time] GC(0)     [ steal-task 867733 868332 ]
[debug][gc,task,time] GC(0) GC-Thread 1 entries: 10
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 861794 861842 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861852 861884 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861884 861886 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861886 861890 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861890 861892 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861892 861893 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861894 862264 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 862265 862271 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 862271 864296 ]
[debug][gc,task,time] GC(0)     [ steal-task 864297 868355 ]
[debug][gc,task,time] GC(0) GC-Thread 2 entries: 4
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 861805 861836 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861845 862009 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 862010 866709 ]
[debug][gc,task,time] GC(0)     [ steal-task 866709 869320 ]
[debug][gc,task,time] GC(0) GC-Thread 3 entries: 9
[debug][gc,task,time] GC(0)     [ thread-roots-task 861818 861964 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861989 861990 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861991 861993 ]
[debug][gc,task,time] GC(0)     [ thread-roots-task 861993 861994 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 861994 861995 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 861995 861997 ]
[debug][gc,task,time] GC(0)     [ scavenge-roots-task 861998 863620 ]
[debug][gc,task,time] GC(0)     [ steal-task 863621 868332 ]
[debug][gc,task,time] GC(0)     [ waitfor-barrier-task 868333 869363 ]

The output confirms that 4 threads were used by the Parallel collector for Young GCs.

Continue to GC(3):

[debug][gc] GC(3) Expanding ParOldGen from 27648K by 27136K to 54784K
[info ][gc,heap     ] GC(3) PSYoungGen: 1520K->0K(25600K)
[info ][gc,heap     ] GC(3) ParOldGen: 25943K->25253K(54784K)
[info ][gc          ] GC(3) Pause Full (Ergonomics) 26M->24M(78M) 17.253ms
[debug][gc,task,time] GC(3) VM-Thread 7386871 7400301 7420455
[debug][gc,task,time] GC(3) GC-Thread 0 entries: 4
[debug][gc,task,time] GC(3)     [ noop task 7386888 7386888 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7386971 7390691 ]
[debug][gc,task,time] GC(3)     [ steal-marking-task 7390691 7393648 ]
[debug][gc,task,time] GC(3)     [ steal-region-task 7400577 7418907 ]
[debug][gc,task,time] GC(3) GC-Thread 1 entries: 5
[debug][gc,task,time] GC(3)     [ noop task 7386870 7386870 ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7386982 ... ]
[debug][gc,task,time] GC(3)     [ steal-marking-task 7391065 7393634 ]
[debug][gc,task,time] GC(3)     [ steal-region-task 7400571 7418883 ]
[debug][gc,task,time] GC(3)     [ waitfor-barrier-task 7418886 7418943 ]
[debug][gc,task,time] GC(3) GC-Thread 2 entries: 4
[debug][gc,task,time] GC(3)     [ noop task 7386901 7386902 ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7386989 ... ]
[debug][gc,task,time] GC(3)     [ steal-marking-task 7388408 7393642 ]
[debug][gc,task,time] GC(3)     [ steal-region-task 7400560 7418900 ]
[debug][gc,task,time] GC(3) GC-Thread 3 entries: 22
[debug][gc,task,time] GC(3)     [ noop task 7386914 7386914 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7386959 7387128 ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387129 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387152 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387153 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387154 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387785 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387787 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387789 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387802 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387804 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387807 ... ]
[debug][gc,task,time] GC(3)     [ thread-roots-marking-task 7387808 ... ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7387810 7387810 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7387811 7387813 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7387813 7387995 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7387996 7388012 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7388012 7388013 ]
[debug][gc,task,time] GC(3)     [ mark-from-roots-task 7388013 7388014 ]
[debug][gc,task,time] GC(3)     [ steal-marking-task 7388014 7393629 ]
[debug][gc,task,time] GC(3)     [ waitfor-barrier-task 7393629 7393662 ]
[debug][gc,task,time] GC(3)     [ steal-region-task 7400476 7418883 ]

The output confirms that 4 threads were used by the Parallel collector for Full GCs.

Conclusion: the Parallel collector may not detect the number cores/logical processors correctly on your Virtualized Windows computer to calculate the number of threads to use. You should use "-XX:ParallelGCThreads" JVM option to specify the number of threads to use by the Parallel collector.

Table of Contents

 About This Book

 Heap Memory Area and Size Control

 JVM Garbage Collection Logging

 Introduction of Garbage Collectors

 Serial Collector - "+XX:+UseSerialGC"

Parallel Collector - "+XX:+UseParallelGC"

 What Is Parallel Collector

 Parallel Collector GC Log Message Format

 Log Message Types from Parallel Collector

 "--Xlog:gc+task+time=debug" - Print GC Threads

"-XX:ParallelGCThreads" - # of Threads

 Parallel Collector Stops Application for Minor/Major GC

 PSYoungGen Collector Using Tenuring Age

 Parallel Collector Changing NewRatio and SurvivorRatio

 Parallel Collector Adaptive Size Policy

 Adaptive Size Policy Log Messages

 "-Xlog:gc+ergo=trace" - Minor GC Report

 Adaptive Size Policy Changed Survivor Space

 Adaptive Size Policy Changed Eden Space

 Adaptive Size Policy for Best Latency

 Parallel Collector Stopped using Young Generation

 Adaptive Size Policy for Best Throughput

 Concurrent Mark-Sweep (CMS) Collector - "+XX:+UseConcMarkSweepGC"

 Garbage First (G1) Collector - "+XX:+UseG1GC"

 The Z Garbage Collector (ZGC) - "+XX:+UseZGC"

 Object References and Garbage Collection

 Garbage Collection Performance Test Program

 Performance Tests on Serial Collector

 Performance Tests on Parallel collector

 Performance Tests on Concurrent collector

 Performance Tests on G1 collector

 Garbage Collection Performance Test Summary

 References

 Full Version in PDF/EPUB