今天查了个 GC 相关的问题,问题并不复杂,只是在比对 GC 日志中的时间与业务超时调用的时间时发现有一点偏差,原来是因为 GC 日志中的时间戳是 GC 开始前的时间戳,而我之前一直以为是 GC 完成后的时间。比如如下 GC 日志:
1 | 2022-12-16T11:10:04.939+0800: 87938160.092: [GC (Allocation Failure) 2022-12-16T11:10:04.939+0800: 87938160.092: [ParNew (promotion failed): 1850515K->1850515K(1850624K), 0.6136336 secs]2022-12-16T11:10:05.552+0800: 87938160.706: [CMS2022-12-16T11:10:06.272+0800: 87938161.426: [CMS-concurrent-mark: 1.702/2.321 secs] [Times: user=0.00 sys=0.00, real=2.32 secs] |
起初我以为 2022-12-16T11:10:04.939 是本次 GC 结束的时间,而实际上这个时间戳表示的是 GC 开始的时间,可以参考源码 jdk8u/genCollectedHeap.cpp at jdk8u362-b06:
1 | void GenCollectedHeap::do_collection(bool full, |
其中第 16 行触发了时间戳的打印,这部分的源码位于 jdk8u/gcTraceTime.cpp at jdk8u362-b06:
1 | GCTraceTime::GCTraceTime(const char* title, bool doit, bool print_cr, GCTimer* timer, GCId gc_id) : |
即在实际的 GC 事件之前进行的打印,从 HBase 自身 JvmPauseMonitor 打印的日志也可以应证这一点:
1 | 2022-12-16 11:10:13,347 INFO [JvmPauseMonitor] util.JvmPauseMonitor(178): Detected pause in JVM or host machine (eg GC): pause of approximately 8143ms |
Reference
Are the timestamps of verbose JVM garbage collection logs the beginning or end of the collection? - Stack Overflow
hbase/JvmPauseMonitor.java at master · apache/hbase · GitHub
HBase应用架构 - 图书 - 豆瓣
Garbage Collection in Java (3) - Concurrent Mark Sweep