Describe the bug
GenerationalHeapParser.splitRemarkReferenceWithWeakReferenceSplitBug(GCLogTrace, String) compiles a regex on every call instead of caching it in a static final field. Regex compilation on a hot parse path is pure overhead and shows up clearly in allocation profiling.
parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java (line ~1920):
public void splitRemarkReferenceWithWeakReferenceSplitBug(GCLogTrace trace, String line) {
GCLogTrace remarkTrace = REMARK_CLAUSE.parse(line);
Pattern durationGroupPattern = Pattern.compile(".* " + PAUSE_TIME); // recompiled every call
Matcher matcher = durationGroupPattern.matcher(line);
...
Every other Pattern.compile in the parser (e.g. AbstractLogTrace, ParNewSerial, PreUnifiedDiarizer) is correctly a static final constant — this call site is the outlier.
Evidence (JFR settings=profile, ~28s run)
Workload: sample Main parsing a 195 MB JDK8 ParallelGC rolling log (gclogs/rolling/jdk8/aagl_prd/gc.log), -Xmx1500m, G1, Java 25 (GraalVM 25.0.3). ~19,985 MB sampled allocations.
Regex compilation (not matching) is visibly present in the allocation-by-site profile:
| Alloc site |
Share |
java.util.regex.Pattern.compile() |
6.83% |
java.util.regex.Pattern.RemoveQEQuoting() (called from compile) |
6.87% |
Compilation should be a one-time startup cost, not ~7% of steady-state allocation.
Expected behavior
Patterns compiled once and reused:
private static final Pattern DURATION_GROUP_PATTERN = Pattern.compile(".* " + PAUSE_TIME);
Additional context
- Audit sibling methods for the same anti-pattern (any in-method
Pattern.compile). The confirmed offending line is GenerationalHeapParser:1920.
- The sample log used here is ParallelGC, so this specific CMS-remark method is not the dominant contributor in this run — but the recompile is still incorrect and will hurt on CMS logs.
- Environment: macOS (Darwin 25.5.0, arm64), Java HotSpot 25.0.3+9-LTS (GraalVM), GCToolkit 3.7.1-SNAPSHOT.
Describe the bug
GenerationalHeapParser.splitRemarkReferenceWithWeakReferenceSplitBug(GCLogTrace, String)compiles a regex on every call instead of caching it in astatic finalfield. Regex compilation on a hot parse path is pure overhead and shows up clearly in allocation profiling.parser/src/main/java/com/microsoft/gctoolkit/parser/GenerationalHeapParser.java(line ~1920):Every other
Pattern.compilein the parser (e.g.AbstractLogTrace,ParNewSerial,PreUnifiedDiarizer) is correctly astatic finalconstant — this call site is the outlier.Evidence (JFR
settings=profile, ~28s run)Workload: sample
Mainparsing a 195 MB JDK8 ParallelGC rolling log (gclogs/rolling/jdk8/aagl_prd/gc.log),-Xmx1500m, G1, Java 25 (GraalVM 25.0.3). ~19,985 MB sampled allocations.Regex compilation (not matching) is visibly present in the allocation-by-site profile:
java.util.regex.Pattern.compile()java.util.regex.Pattern.RemoveQEQuoting()(called from compile)Compilation should be a one-time startup cost, not ~7% of steady-state allocation.
Expected behavior
Patterns compiled once and reused:
Additional context
Pattern.compile). The confirmed offending line isGenerationalHeapParser:1920.