In the production environment, or other environments where GC issues are to be tested, the parameters for printing GC logs must be configured to facilitate the analysis of GC-related issues.

But probably many people don’t configure it “perfectly”, either too little is printed, or output to the console, or a large file is overwritten, or…

This article takes you step by step, configuring a perfect GC log printing strategy

to print


in order to retain enough “live evidence”, it is best to print GC-related information complete enough. And your program is really not bad for the performance of your GC when printing log I/O consumptionPrinting

basic GC


first step in printing GC logs is to open the parameters of GC printing, which is also the most basic parameter.

-XX:+PrintGCDetails -XX:+PrintGCDateStampsPrint

Object Distribution

In order to analyze the promotion situation at GC and the high pause caused by promotion, do not look at the

object age distribution log -XX: +PrintTenuringDistribution

output example:

 Desired survivor size 59244544 bytes, new threshold 15 (max 15)- age   1:     963176 bytes,     963176 total- age   2:     791264 bytes,    1754440 total- age   3:     210960 bytes,    1965400 total- age   4:     167672 bytes,    2133072 total- age   5:     172496 bytes,    2305568 total- age   6:     107960 bytes,    2413528 total- age   7:     205440 bytes,    2618968 total- age   8:     185144 bytes,    2804112  total- age   9:     195240 bytes,    2999352 total- age  10:     169080 bytes,    3168432 total- age  11:     114664 bytes,    3283096 total- age  12:     168880 bytes,    3451976 total- age  13:     167272  bytes, 3619248 total- age 14: 387808 bytes, 4007056 total- age 15: 168992 bytes, 4176048 total


print heap data

Every time GC occurs, compare the heap memory before and after GC, more intuitive

 -XX: +PrintHeapAtGC

output example:

 {Heap before GC invocations=0 (full 0): garbage-first heap   total 1024000K, used 324609K [0x0000000781800000, 0x0000000781901f40, 0x00000007c0000000)  region size 1024K, 6 young (6144K), 0 survivors (0K) Metaspace       used 3420K, capacity 4500K, committed 4864K, reserved 1056768K  class space    used 371K, capacity 388K, committed 512K, reserved 1048576KHeap after GC invocations=1 ( full 1): garbage-first heap   total 1024000K, used 21755K [0x0000000781800000, 0x0000000781901f40, 0x00000007c0000000)  region size 1024K, 0 young (0K), 0 survivors (0K) Metaspace       used 3420K, 

capacity 4500K, committed 4864K, reserved 1056768K class space used 371K, capacity 388K, committed 512K, reserved 1048576K}

Print STW


pause time is the most important indicator of GC, certainly not less


Output example:

Total time for which  application threads were stopped: 0.0254260 seconds, Stopping threads took: 0.0000218 seconds

Before printing

safepoint information

enters the STW phase, you need to find a suitable safepoint. This indicator is also very important (not required, it is best to add this parameter to debug when there is a GC problem)

-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1Output


          vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count0.371: ParallelGCFailedAllocation       [      10          0              0    ]      [     0     0     0     0     7    ]  0   Execute full gc... dataList has been promoted to cms old space         vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count0.379: ParallelGCSystemGC               [      10          0              0    ]      [     0     0     0     0    16    ]  0            vmop                    [threads: total initially_running wait_to_block]    [time: spin block sync cleanup vmop] page_trap_count0.396: no vm operation                  [       9          1              1    ]      [ 0 0 0 0 341 ] 0 

Print Reference Processing InformationStrong


/Weak Reference/Soft Reference/Virtual Reference/Finalize Method If there is a problem, must it not be printed out to see?


output example:

 2021-02-19T12:41:30.462+0800: 5072726.605: [SoftReference, 0 refs, 0.0000521 secs]2021-02-19T12:41:30.462+0800: 5072726.605: [WeakReference, 0 refs, 0.0000069 secs]2021-02-19T12 :41:30.462+0800: 5072726.605: [FinalReference, 0 refs, 0.0000056 secs]2021-02-19T12:41:30.462+0800: 5072726.605: [PhantomReference, 0 refs, 0 refs, 0.0000059 secs]2021-02-19T12 :41:30.462+0800:5072726.605: [JNI Weak Reference, 0.0000131 secs], 0.4635293 secs]

Full parameter

# requireds -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintReferenceGC -XX:+PrintGCApplicationStoppedTime

# optional

-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1


Just what is printed is defined above, and by default, these logs are output to the console (standard output). So if your program log is also output to the console, the log content will be very messy, and it will be very troublesome to analyze. If you append (e.g. tomcat’s catalina.out is append), the file will get bigger and bigger, and the analysis will be fatal.

So there needs to be a mechanism for dividing the log, this mechanism… JVM is naturally provided.



splittingJVM provides several parameters for splitting GC logs

: # File path of

GC log output -Xloggc:/path/to/gc

.log# Enable log file splitting

-XX:+ UseGCLogFileRotation #

Split up to a few files, after which you write from scratch


# Maximum size per file, exceeding which triggers splitting


According to this parameter, each GC log will be split as long as it exceeds 20M, and up to 5 files will be split, and the file names are

gc.log.0, gc.log.1, gc.log.2, gc.log.3, gc.log.4, …….

It seems very beautiful, but a few lines of configuration solve the problem of the output file. But there are some problems with this method:

the log file specified by the

    -Xloggc mode is the way to overwrite the write, which will be overwritten every time it is started, and the history log will be lost When the maximum number of splits is exceeded, it will be rewritten from

  • the 0th
    file, and it is overwritten
  • -XX: NumberOfGCLogFiles can’t be set to infinite

The problem of this override is a bit disgusting, the history log before each startup overwrite… Who can endure this?

Naming files with timestamps

has another solution. Instead of using the log splitting feature provided by the JVM, the log file is named with a timestamp for each boot, so that a different file is used for each boot and there is no overwriting problem.

# Use -%t as the log file name -XX:+

PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/path/to/gc-%t.log# The generated file name is this: gc-2021-03-29_20-41-47.

Is log


While there is

no overriding issue, since there is no log splitting feature, there is only one GC log file after each boot, and a single log file can be very large. Large log files are cumbersome to analyze and must be divided.

The combination of

the two

here only needs to adjust the strategy slightly, and combine the two schemes of JVM segmentation and timestamp naming to get the optimal way.

# The file path of GC log output - Xloggc:/path/to/gc-%t

.log# Enable log file splitting-XX


# Split up to a few files, after which you can write from scratch


# The maximum size of each file, if it exceeds it, it triggers splitting-XX


Configure the timestamp composition GC log file name and also configure the GC log segmentation policy of JVM. In this way, it not only ensures that the GC file will not be overwritten, but also ensures that the size of a single GC file will not be too large, perfect!

The resulting log file name would look like this:


  • .log.0 gc-2021-03-29_20-41-47.log.1
  • gc-2021-03-29_20-41-47.log.2
  • gc-2021-03-29_20-41-47.log.3
  • ….

Best Practice – Full Parameters

# Required -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintReferenceGC -XX:+PrintGCApplicationStoppedTime

# Optional

-XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1# File path of GC log



.log# Turn on log file splitting

-XX:+ UseGCLogFileRotation #

Split up to several files, after which you start writing -


# Maximum size of each file, exceeding which triggers splitting