The Current Java HotSpot VM includes three different types of collectors, each with different performance characteristics. There are three main operations which garbage collector is responsible for:
- finding objects which are no longer used
- freeing up the memory after those objects
- compacting the heap.
Not all the collectors perform those operations in the same way, so let’s go through the basic overview of GC Collectors.
GC (Garbage Collection) Collectors
- Serial Collector
- Parallel Collector
- The Mostly Concurrent Collector
As the name suggests, serial collector uses a single thread to perform all garbage collection work, which makes it relatively efficient because there is no communication overhead between threads.
Serial GC is best-suited to single processor machines because it can’t take advantage of multiprocessor hardware. Although it can be useful on multiprocessors for applications with small data sets (up to approximately 100 MB).The Serial GC can be enabled with the option
-XX:+UseSerialGC. On certain hardwares and operating system configurations, serial collector is selected by default.
Parallel Collector (Throughput Collector)
The parallel collector is also known as throughput collector, it’s a generational collector similar to the serial collector. The primary difference between the serial and parallel collectors is that the parallel collector has multiple threads that are used to speed up garbage collection.
The parallel collector is intended for applications with medium-sized to large-sized data sets that are run on multiprocessor or multithreaded hardware. You can enable it by using the
Since JDK 7u4, the Old Generation is also collected by multiple threads by default. Prior to JDK 7u4,
-XX:+UseParallelOldGC flag was required to enable parallel processing of the Old Generation. Now, both
-XX:+UseParallelOldGC flags enable Throughput Collector with parallel processing of both the Old and Young Generations.
To configure the number of GC threads you can use
-XX:ParallelGCThreads=X flag. The default value is set to the number of CPU cores.
The Mostly Concurrent Collector
They are so called low pause collectors – designed to minimize stop-the-world pauses and to keep the application as responsive as possible. Concurrent Mark and Sweep (CMS) collector and Garbage-First (G1) garbage collector are the two mostly concurrent collectors. Mostly concurrent collectors perform some expensive work concurrently to the application.
Garbage First (G1) is a server-style collector for multiprocessor machines with a large amount of memory. It meets garbage collection pause-time goals with high probability, while achieving high throughput. G1 is designed to process large heaps with minimal pauses. The heap is broken down into several regions of fixed size (while still maintaining the generational nature of the heap). That kind of design allows us to get rid of long STW pauses when the entire Young or Old Generations are processed. Now, each region can be collected separately which leads to shorter, but more frequent STW pauses. G1 copies objects from one region into another, which means that the heap is at least partially compacted.
G1 uses an incremental version of the mark-sweep-compact algorithm. It can be enabled by specifying
Concurrent Mark and Sweep (CMS)
This collector is for applications that prefer shorter garbage collection pauses and can afford to share processor resources with the garbage collection. Minor GC is performed with multiple threads using the parallel mark-copy algorithm. All application threads are stopped then. The Old Generation is mostly collected concurrently – application threads are paused for very short periods of time when the background GC thread scans the Old Generation. The actual algorithm used during Major GC is concurrent mark-sweep. Concurrent Mark and Sweep is the collector which doesn’t compact the Tenured space and thus the memory can be left fragmented.
Use the option
-XX:+UseConcMarkSweepGC to enable the CMS collector.
Selecting the Collector
It’s always a good practice to first run your application and allow the VM to select a collector, unless your application has rather strict pause-time requirements.
If necessary, adjust the heap size to improve performance. If the performance still doesn’t meet your goals, then use the following guidelines as a starting point for selecting a collector:
- Select the serial collector with the option
- If the application has a small data set (approximately 100 MB).
- If the application will be run on a single processor and there are no pause-time requirements.
- If (a) peak application performance is the first priority and (b) there are no pause-time requirements or pauses of one second or longer are acceptable, then let the VM select the collector or select the parallel collector with
- If response time is more important than overall throughput and garbage collection pauses must be kept shorter than approximately one second, then select a concurrent collector with
The above specified points provide a starting point for selecting a collector because performance is dependent on:
- the size of the heap.
- the amount of live data maintained by application.
- the number and speed of available processors.
Pause-time is particularly sensitive to these factors, so the threshold of one second mentioned previously is only approximate. The parallel collector will experience a pause time longer than one second on many heap size and hardware combinations. Conversely, the concurrent collectors may not be able to keep pauses shorter than one seconds in some cases.