From 71f483960ba343a5fb421a7cf96caa695caf60c8 Mon Sep 17 00:00:00 2001 From: eddie Date: Tue, 7 Apr 2026 14:09:07 +0800 Subject: [PATCH 1/2] fix: disable lockedSynchronizers in dumpAllThreads to avoid safepoint heap scan (#16194) `ThreadMXBean.dumpAllThreads(true, true)` with lockedSynchronizers=true forces the JVM to scan the entire heap at a safepoint to find all AbstractOwnableSynchronizer instances. On ZGC with large heaps (65GB+), this causes ~37-second safepoint pauses that freeze all application threads, leading to cascading thread pool exhaustion. Change lockedSynchronizers from true to false. This retains locked monitor information (derived from thread stacks, cheap) but skips the expensive heap scan. Only java.util.concurrent.locks ownership info is lost from the thread dump output. Fixes #16194 --- .../main/java/org/apache/dubbo/common/utils/JVMUtil.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java index 146e351e0895..7d7d05476956 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java @@ -33,7 +33,12 @@ public class JVMUtil { public static void jstack(OutputStream stream) throws Exception { ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); - for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, true)) { + // Pass lockedSynchronizers=false to avoid a full heap scan at safepoint. + // With lockedSynchronizers=true, the JVM iterates the entire heap to find all + // AbstractOwnableSynchronizer instances. On ZGC with large heaps, this causes + // tens-of-seconds safepoint pauses due to load barrier overhead on every reference. + // See: https://github.com/apache/dubbo/issues/16194 + for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, false)) { stream.write(getThreadDumpString(threadInfo).getBytes(StandardCharsets.UTF_8)); } } From b12b3ccf60d3d9530ff767c8ef5a7f0553dd377e Mon Sep 17 00:00:00 2001 From: eddie Date: Tue, 7 Apr 2026 14:12:54 +0800 Subject: [PATCH 2/2] chore: remove inline comments from JVMUtil.jstack() Context is documented in the issue and PR description. Fixes #16194 --- .../src/main/java/org/apache/dubbo/common/utils/JVMUtil.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java index 7d7d05476956..1ea41c5ab573 100644 --- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java +++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/JVMUtil.java @@ -33,11 +33,6 @@ public class JVMUtil { public static void jstack(OutputStream stream) throws Exception { ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean(); - // Pass lockedSynchronizers=false to avoid a full heap scan at safepoint. - // With lockedSynchronizers=true, the JVM iterates the entire heap to find all - // AbstractOwnableSynchronizer instances. On ZGC with large heaps, this causes - // tens-of-seconds safepoint pauses due to load barrier overhead on every reference. - // See: https://github.com/apache/dubbo/issues/16194 for (ThreadInfo threadInfo : threadMxBean.dumpAllThreads(true, false)) { stream.write(getThreadDumpString(threadInfo).getBytes(StandardCharsets.UTF_8)); }