## Symptom
If the zgc threads are blocked (or unable to be scheduled) for some time, the update of "_nticks" in ZMetronome::wait_for_tick() may become incorrect.
For example, zgc threads can be blocked at a breakpoint when debugging with GDB.
A lot of unexpected gc+stats logs might be observed due to the incorrect "_nticks".
## Reproduce
- Running script
---------------------------------------------------------
gdb --args \
${JDK}/bin/java \
-Xlog:gc* \
-XX:+UnlockExperimentalVMOptions \
-XX:-UseG1GC -XX:+UseZGC \
SomeJavaAppWithGCs
---------------------------------------------------------
- Set a GDB breakpoint
---------------------------------------------------------
(gdb) b ZDriver::concurrent_mark()
Function "ZDriver::concurrent_mark()" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (ZDriver::concurrent_mark()) pending.
(gdb) handle SIGSEGV nostop noprint
Signal Stop Print Pass to program Description
SIGSEGV No No Yes Segmentation fault
(gdb) r
---------------------------------------------------------
- Do some check at the breakpoint (or just wait for some time), and then continue
---------------------------------------------------------
Breakpoint 1, ZDriver::concurrent_mark (this=0x7ffff004f3c0) at /home/fool/Workspace/jdk/src/hotspot/share/gc/z/zDriver.cpp:278
278 ZStatTimer timer(ZPhaseConcurrentMark);
(gdb)
(gdb) do some check here, or just wait for some time (e.g., 60s)
... after some time ...
(gdb) c
... a lot of unexpected gc+stats logs were printed ...
---------------------------------------------------------
## Fix
---------------------------------------------------------
diff -r b0b20413d853 src/hotspot/share/gc/z/zMetronome.cpp
--- a/src/hotspot/share/gc/z/zMetronome.cpp Wed May 15 11:53:47 2019 +0200
+++ b/src/hotspot/share/gc/z/zMetronome.cpp Wed May 15 20:15:39 2019 +0800
@@ -57,6 +57,8 @@
if (!_stopped && timeout_ms > 0) {
// Wait
ml.wait(timeout_ms);
+ } else if (timeout_ms < -1 * (int64_t)_interval_ms) {
+ _nticks += -timeout_ms / _interval_ms;
} else {
// Tick
return !_stopped;
---------------------------------------------------------
If the zgc threads are blocked (or unable to be scheduled) for some time, the update of "_nticks" in ZMetronome::wait_for_tick() may become incorrect.
For example, zgc threads can be blocked at a breakpoint when debugging with GDB.
A lot of unexpected gc+stats logs might be observed due to the incorrect "_nticks".
## Reproduce
- Running script
---------------------------------------------------------
gdb --args \
${JDK}/bin/java \
-Xlog:gc* \
-XX:+UnlockExperimentalVMOptions \
-XX:-UseG1GC -XX:+UseZGC \
SomeJavaAppWithGCs
---------------------------------------------------------
- Set a GDB breakpoint
---------------------------------------------------------
(gdb) b ZDriver::concurrent_mark()
Function "ZDriver::concurrent_mark()" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (ZDriver::concurrent_mark()) pending.
(gdb) handle SIGSEGV nostop noprint
Signal Stop Print Pass to program Description
SIGSEGV No No Yes Segmentation fault
(gdb) r
---------------------------------------------------------
- Do some check at the breakpoint (or just wait for some time), and then continue
---------------------------------------------------------
Breakpoint 1, ZDriver::concurrent_mark (this=0x7ffff004f3c0) at /home/fool/Workspace/jdk/src/hotspot/share/gc/z/zDriver.cpp:278
278 ZStatTimer timer(ZPhaseConcurrentMark);
(gdb)
(gdb) do some check here, or just wait for some time (e.g., 60s)
... after some time ...
(gdb) c
... a lot of unexpected gc+stats logs were printed ...
---------------------------------------------------------
## Fix
---------------------------------------------------------
diff -r b0b20413d853 src/hotspot/share/gc/z/zMetronome.cpp
--- a/src/hotspot/share/gc/z/zMetronome.cpp Wed May 15 11:53:47 2019 +0200
+++ b/src/hotspot/share/gc/z/zMetronome.cpp Wed May 15 20:15:39 2019 +0800
@@ -57,6 +57,8 @@
if (!_stopped && timeout_ms > 0) {
// Wait
ml.wait(timeout_ms);
+ } else if (timeout_ms < -1 * (int64_t)_interval_ms) {
+ _nticks += -timeout_ms / _interval_ms;
} else {
// Tick
return !_stopped;
---------------------------------------------------------