Auto-tune JVM GC algorithm in setenv.sh based on available vCPUs
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 970
- Forks
- 486
- Avg merge
- 3d 33m
- Merged PRs (30d)
- 170
Description
Description
The Tomcat setenv.sh startup script uses a static GC configuration regardless of the container's available CPU resources. On Java 25 we can make smarter, automatic GC choices that improve throughput and latency without any operator tuning.
Current behavior
JAVA_OPTS_MEMORY is a hardcoded string with G1PeriodicGCInterval=10000 applied unconditionally, regardless of whether the container has 1 vCPU or 32.
Proposed behavior
Detect available vCPUs at container startup and select the appropriate GC:
| vCPUs | GC selected | Rationale |
|---|---|---|
| 1–3 | G1GC (default) + G1PeriodicGCInterval=10000 |
Returns memory to OS on idle; low overhead on small containers |
| 4+ | ZGC (-XX:+UseZGC) |
Java 25 defaults to GenerationalZGC; sub-millisecond pauses; scales with cores |
SerialGC is explicitly excluded — it is not appropriate for a long-running, multi-threaded web server (Tomcat threads, Quartz, OSGi, async jobs) even on a single-core container.
CPU count detection:
_cpus=$(nproc 2>/dev/null || grep -c '^processor' /proc/cpuinfo 2>/dev/null || echo 2)
Base memory flags remain constant across all tiers:
-XX:MaxRAMPercentage=72.0-XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50-Djdk.nio.maxCachedBufferSize=262144
Full override: set JAVA_OPTS_MEMORY before the script runs — auto-tune is skipped entirely.
Acceptance Criteria
To be refined. (Quick draft — details to be added.)
- On a 1-vCPU container, G1GC +
G1PeriodicGCInterval=10000is selected at startup - On a 4+-vCPU container,
-XX:+UseZGCis selected at startup - Startup log prints the selected GC and detected vCPU count
- Setting
JAVA_OPTS_MEMORYexternally bypasses auto-selection entirely - SerialGC is never selected
Additional Context
- Java 25 GenerationalZGC is the default ZGC mode —
-XX:+UseZGCalone is sufficient - The direct memory block (
JAVA_OPTS_DIRECT) already uses a similar cgroup-aware auto-tune pattern; this change follows the same idiom MaxRAMPercentageandjdk.nio.maxCachedBufferSizedo not need to scale with CPU count
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in setenv.sh and compare the existing cgroup-aware pattern in the JAVA_OPTS_DIRECT block. Trace how JAVA_OPTS_MEMORY is initialized and overridden, then verify startup output and JVM flags for 1–3 and 4+ vCPUs, including that an external override bypasses auto-selection and SerialGC is never chosen.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, shell
- Domain
- devops, infrastructure
- Issue type
- Feature
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100