Reading a GC log
Three numbers answer nearly every question: pause length, pause frequency, and live set after a full GC.
Open this lesson in the learning hubKey points
- Unified logging since Java 9:
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=10M. The old flags are gone. - A young line reads
Pause Young ... 512M->48M(1024M) 6.2ms: heap before, heap after, total heap, pause. - The number that matters is the one after a full GC. If it climbs run after run that is retention, and no flag will help.
- Allocation rate is bytes reclaimed per second across young pauses. A high rate with short pauses is healthy, not a problem.
- In G1, watch for
to-space exhaustedandHumongousallocations. Both say the heap or the region size is wrong. - Compare total pause time against wall clock. Under 5% is normal; above 10% you are paying real money for the collector.
Example
# turn it on - rotate the files so it is safe to leave running
java -Xlog:gc*:file=/var/log/app/gc.log:time,uptime,level,tags:filecount=5,filesize=10M -jar app.jar
# a healthy young collection: 512 MB of eden became 48 MB of survivors in 6 ms
# [2026-03-04T09:12:44.108+0000][121.402s][info][gc] GC(418) Pause Young (Normal)
# (G1 Evacuation Pause) 512M->48M(1024M) 6.211ms
# the line that actually matters - the live set after a full collection
# [ ... ][info][gc] GC(41) Pause Full (G1 Compaction Pause) 1004M->812M(1024M) 1402ms
# [ ... ][info][gc] GC(58) Pause Full (G1 Compaction Pause) 1010M->889M(1024M) 1511ms
# [ ... ][info][gc] GC(77) Pause Full (G1 Compaction Pause) 1018M->951M(1024M) 1633ms
# ^ 812 -> 889 -> 951
# and the two shapes that mean the heap layout is wrong
grep -E "to-space exhausted|Humongous" gc.log | head
Read the heap size after a full GC before you read anything else.
This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the JVM course, and every lesson in it is listed on the JVM contents page.