"-XX:ParallelGCThreads=n" - # of Threads

This section describes how to use the '-XX:ParallelGCThreads=n' 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 4 parallel threads to perform both minor and major 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. At values of N below 8, the number used is N. On selected platforms, the fraction drops to 5/16.

The output from the previous tutorial did confirm what's said in Java documentation. The Parallel collector used 4 parallel threads, because my Windows computer has 2 cores and 4 logical processors.

To control the number of parallel treads explicitly, we can use the "-XX:ParallelGCThreads=n" JVM option. In the example below, we are running our test program with 2 parallel threads:

herong> \progra~1\java\jdk1.8.0\bin\java -Xms2m -Xmx64m -XX:+UseParallelGC \
   -XX:+PrintGCDetails -XX:+PrintGCTimeStamps \
   -XX:-XX:ParallelGCThreads=2 -XX:+PrintGCTaskTimeStamps \
   GarbageCollection > output.txt
(Ctrl-C)

herong> more output.txt
Step/TotalMemory/FreeMemory/UsedMemory:
0.768: [GC (Allocation Failure)
   [PSYoungGen: 511K->248K(768K)] 1280K->1176K(1792K), 0.0020402 secs]
   [Times: user=0.00 sys=0.03, real=0.02 secs]
VM-Thread 1801012 1805624 1806301
GC-Thread 0 entries: 13
  [ old-to-young-roots-task 1801893 1801928 ]
  [ scavenge-roots-task 1801932 1802032 ]
  [ thread-roots-task 1802034 1802044 ]
  [ thread-roots-task 1802045 1802054 ]
  [ thread-roots-task 1802055 1802058 ]
  [ thread-roots-task 1802059 1802683 ]
  [ thread-roots-task 1802684 1802687 ]
  [ scavenge-roots-task 1802688 1802693 ]
  [ scavenge-roots-task 1802694 1802697 ]
  [ scavenge-roots-task 1802698 1802702 ]
  [ scavenge-roots-task 1802702 1802716 ]
  [ scavenge-roots-task 1802717 1805389 ]
  [ steal-task 1805390 1805579 ]
GC-Thread 1 entries: 9
  [ old-to-young-roots-task 1801918 1801946 ]
  [ scavenge-roots-task 1801949 1802049 ]
  [ thread-roots-task 1802052 1802061 ]
  [ thread-roots-task 1802062 1802462 ]
  [ thread-roots-task 1802463 1802946 ]
  [ scavenge-roots-task 1802947 1802950 ]
  [ scavenge-roots-task 1802951 1802952 ]
  [ steal-task 1802952 1805547 ]
  [ waitfor-barrier-task 1805548 1805615 ]

0.771: [Full GC (Ergonomics) [PSYoungGen: 248K->246K(768K)]
   [ParOldGen: 928K->921K(1792K)] 1176K->1168K(2560K),
   [Metaspace: 1555K->1555K(4480K)], 0.0050992 secs]
VM-Thread 1807541 1812770 1819510
GC-Thread 0 entries: 16
  [ noop task 1807518 1807528 ]
  [ mark-from-roots-task 1807603 1807983 ]
  [ thread-roots-marking-task 1807984 1808006 ]
  [ thread-roots-marking-task 1808006 1808522 ]
  [ thread-roots-marking-task 1808523 1808525 ]
  [ mark-from-roots-task 1808526 1808529 ]
  [ mark-from-roots-task 1808529 1808532 ]
  [ mark-from-roots-task 1808532 1808535 ]
  [ mark-from-roots-task 1808535 1808571 ]
  [ mark-from-roots-task 1808571 1808572 ]
  [ mark-from-roots-task 1808572 1808574 ]
  [ mark-from-roots-task 1808574 1808575 ]
  [ steal-marking-task 1808575 1809423 ]
  [ drain-region-task 1814309 1817604 ]
  [ steal-region-task 1817605 1817608 ]
  [ waitfor-barrier-task 1817608 1818582 ]
GC-Thread 1 entries: 14
  [ noop task 1807503 1807504 ]
  [ mark-from-roots-task 1807746 1807764 ]
  [ thread-roots-marking-task 1807765 1807771 ]
  [ thread-roots-marking-task 1807772 1807777 ]
  [ thread-roots-marking-task 1807777 1807778 ]
  [ thread-roots-marking-task 1807779 1807780 ]
  [ thread-roots-marking-task 1807780 1809401 ]
  [ steal-marking-task 1809402 1809405 ]
  [ waitfor-barrier-task 1809405 1809452 ]
  [ drain-region-task 1812810 1816131 ]
  [ update-dense_prefix-task 1816134 1816156 ]
  [ update-dense_prefix-task 1816157 1816161 ]
  [ update-dense_prefix-task 1816161 1816164 ]
  [ steal-region-task 1816165 1818377 ]
...

From the output, I can see that the Parallel Collector did use 2 multiple threads to perform the first Minor GC and the first Major GC as we specified.

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

 "-XX:+PrintGCTaskTimeStamps" - Print GC Threads

"-XX:ParallelGCThreads=n" - # 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

 "-XX:+PrintAdaptiveSizePolicy" - Minor GC Report

 Adaptive Size Policy Changed Survivor Space

 Adaptive Size Policy Changed Eden Space

 Adaptive Size Policy for Best Latency

 Adaptive Size Policy for Best Throughput

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

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

 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

 Archived Tutorials

 References

 Full Version in PDF/EPUB