The heap memory may have objects allocated to it in a non-contiguous manner. This allocation may leave small spaces of free memory, causing fragmentation of the heap. If these free spaces are smaller than the minimum thread local area (TLA), then they cannot be used for object allocation.
These small free spaces go unused until enough space is placed next to them during the next garbage collection.
Compaction serves as a way to bring objects together and leave a large space that can be used for object allocation. It achieves this by moving blocks of allocated memory to the lower end of the heap, thus leaving a large contiguous free space at the top.
It’s important to note that compaction happens during garbage collection. Therefore, having large chunks of memory to compact, will lead to long pause times. However, having little compaction will cause fragmentation & hence negatively impact your application’s performance.
Generally, the JVM does a good job at compaction. Although, if you notice periodic degradation in your application’s performance, then you can consider taking some action & observe what happens. Fluctuating values for throughput and response time for your application may be some of the smoking signals. Large garbage collections with long pauses should also be of interest to you.
You can tune your JVM for parallel compaction by turning on the -XX:+UseParallelOldGC flag. This will ensure that both minor and major collections are carried out in parallel, hence reducing the garbage collection overhead.
By default, major collections are carried out by a single thread, while minor collections are done using multiple threads. Therefore, using the -XX:+UseParallelOldGC should reduce the latency on a multiprocessor system.