Java Heap fragmentation is an interesting problem, which triggers long pausing full garbage collection cycles. In this article we would like to attempt to explain the heap fragmentation.
Let’s say developer write a code ‘new BMW()’. This will create a new BMW object in the heap memory space. Example:
Fig: New object created in JVM Heap
Let’s say now application creates 3 more new objects: ‘Toyota’, ‘Honda’, ‘Tesla’. Now JVM’s heap memory will start to look like this:
Fig: More objects are created in JVM Heap
Let’s say after some time, no other objects are referencing Toyota and Tesla objects, then garbage collector will remove Toyota and Tesla objects from the memory. Thus, after garbage collection cycle now heap memory will start to look like this:
Fig: Garbage collection removes unused objects from JVM Heap
Let’s say now application is creating a new ‘Truck’ object which is bigger in size. Even though there is sufficient space to accommodate Truck object in memory, there isn’t enough contiguous space to store the Truck object in the memory, because heap is fragmented.
Fig: JVM heap is fragmented, there is not enough contiguous space to accommodate ‘Truck’ object
When heap is fragmented like this Full Garbage Collection is triggered. Full GC will start compacting the memory i.e. it move BMW and Honda objects next to each other, so that there is enough contiguous memory. Typically, Full GC which does the compaction ends up pausing JVM for a longer duration.
Note: To study the amount of heap fragmentation and pause times incurred by your application due to Full garbage collection cycles and steps to reduce them you may consider using free garbage collection log analysis tools like GCeasy, Garbage Cat, HP Jmeter.
Fig: JVM Heap after compaction
After compaction there will be sufficient contiguous memory to store the Truck object into memory. Thus, Truck object can be stored in memory.
Fig: JVM heap able to accommodate ‘Truck’ object after compaction
July 2, 2020 at 3:31 pm
I understood the fragmentation in the heap but the Full GC take very long pause, for example in my case the Heap is 30 GB and it is taking more than 180 second in Full GC. How can we avoid such situation where my application need to wait for so long time for Full GC.
June 17, 2020 at 3:59 pm
Agree with Jack. Also would like to see how the allocation occurs. If an object is 3.5MB, does it allocate 3.5MB, or does it allocate in chunks? How fragmented does memory need to be to start a gc? Or is it a single object is being stored in non-contiguous space, so full gc starts?
June 19, 2020 at 12:02 am
Hello @steve! If the object size is 3.5mb, it has to be allocated contiguously in memory. It can’t be allocated in chuncks.
When the heap is heavily fragmented and doesn’t have contiguous space to store new objects, full GC will be triggered.
June 9, 2020 at 10:42 pm
Good post, but missing some key info. What happens when heap is compacted? What does compaction actually do internally? moves the object to the bottom of the heap etc?