I've read an extensive amount of documentation about the HotSpot GC of Java SE 6 and 7. When talking about strategies for obtaining contiguous regions of free memory, two 'competing' approaches are presented: that of Evacuation (usually applied on the young gen), where live objects are copied from 'from' to an empty 'to' and that of Compaction (fall-back of CMS), where live object are moved to one side inside a fragmented region to form a contiguous block of used an unused memory.
Both approaches are proportional to the size of the 'live set'. The difference is that evacuation requires x2 times space than the live set, where the compaction does not.
Why do we need the Evacuation technique at all? The amount of copying that needs to be done is the same, however it requires reservation of more heap size, and it does not allow for faster remapping of references.
True: the evacuation can be executed in parallel (where-as compaction cannot, or at least not as easily) but this trait is never mentioned and seems not that important (considering that remapping is much more expensive than moving).
When the garbage has been removed from the heap, the Garbage Collector can consider compacting the resulting set of objects to remove the spaces that are between them. The process of compaction is complicated because, if any object is moved, the GC must change all the references that exist to it.
There are two ways to do it : Using System. gc() method: System class contain static method gc() for requesting JVM to run Garbage Collector. Using Runtime.
Garbage collection then goes through the three phases: mark, sweep, and, if required, compaction.
One difference is that G1 is a compacting collector. Also, G1 offers more predictable garbage collection pauses than the CMS collector, and allows users to specify desired pause targets. As with CMS, G1 is designed for applications that require shorter GC pauses.
One big problem is that with "evacuation" the vacated space is, indeed vacant, while with "compaction" some other object Y may be moved into the space where object X was. This makes it a lot harder to correct pointers, since one can't simply use the fact that a pointer points to an invalid location to clue the code that it needs to be updated. And one can't store the "forwarding pointer" in the "invalid" location.
This makes GC much less concurrent -- the app must be in "GC freeze" for a longer period of time.
Compaction is more suitable in cases where the number of reclaimable objects is expected to be low(e.g. Tenured generation) because after a few GC cycles the long living objects tend to occupy the lower portion of the heap and hence less work is needed to be done by the collector. If in such a case a copying collector is used that would perform very poorly because almost the same surviving objects from the previous cycles will need to be copied again and again from one location to the other.
Copying is suitable when the number of reclaimable objects is very high(e.g. Young generation) since very few surviving objects needs to be copied. If in such a case compaction is used that may perform poorly because the surviving objects may be scattered across the heap.
Other than that as mentioned in @Hot Licks answer Copying collector allows us to store a forwarding pointer which prevents from running into an infinite loop in case another object from the same "From" space refers to an already moved object.
Also, Compaction can not begin until all the live objects are identified, but live objects can be copied to the new location as soon as they are identified(using multiple threads).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With