feat(mem): JDK 25 UseCompactObjectHeaders #35931
Open
wezell wants to merge 18 commits into
Open
Conversation
Reapplies the Java 25 part-2 changes on top of current main, keeping main's configurable dotcms.core.compiler.release mechanism but flipping its default from 11 to 25 so core compiles to Java 25 bytecode by default (override with -Ddotcms.core.compiler.release=11 for older compatibility). - .sdkmanrc / docker/java-base: build/runtime JDK -> 25.0.2-ms - parent/pom.xml: dotcms.core.compiler.release default 11 -> 25, jdk.min.version -> 25, glowroot -> 0.14.5-beta.3-java25 - test-jmeter / test-karate: compiler source/target/release -> 25 - CLAUDE.md: runtime references 21 -> 25 - Add Java 25 problems/solutions and smoke-test docs Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…es, align docs
- test-jmeter / test-karate: use ${dotcms.core.compiler.release} instead of
hardcoded 25 so the -Ddotcms.core.compiler.release override applies uniformly
- CLAUDE.md: resolve Java 11-syntax vs default-25-bytecode contradiction; core
now compiles to Java 25 by default (override-able), runtime is Java 25
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drop JAVA25_PROBLEMS_AND_SOLUTIONS.md and JAVA25_SMOKE_TEST.md from the source tree per review feedback — operational/migration notes belong outside the versioned source. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ith compact object headers Enable project-wide --enable-preview (JDK 25) so core can use java.lang.StableValue (JEP 502), and update the container JVM flags. Container runtime (setenv.sh): - Replace ZGC (-XX:+UseZGC -XX:+ZGenerational) with -XX:+UseG1GC - Add -XX:+UseCompactObjectHeaders (product flag on JDK 25, JEP 519) - Add --enable-preview - Drop -XX:+UnlockExperimentalVMOptions (no longer needed) Build wiring (parent/pom.xml): - New property maven.compiler.enablePreview=true, wired into maven-compiler-plugin - Add --enable-preview and -XX:+UseCompactObjectHeaders to surefire + failsafe argLines - .mvn/jvm.config carries --enable-preview so compile-phase plugins (swagger-maven-plugin) can classload preview-stamped (0xFFFF) core classes Pinned-to-Java-11 modules set enablePreview=false (javac rejects --enable-preview at --release 11): dotcms-cli, tika-api, tika-plugin. Add StableValuePreviewTest smoke test (surefire): fails the build if preview support regresses and asserts -XX:+UseCompactObjectHeaders is active under surefire. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Container runtime (setenv.sh), validated against dotcms/dotcms:java-25 and the certified mcr.microsoft.com/openjdk/jdk:25-ubuntu jaz build: Heap/GC (mirrors jaz's profile, which it applies only when no -X/-XX flag is set; since we set tuning flags explicitly, jaz is hands-off but still does crash-dump + graceful SIGTERM): - -XX:+UseG1GC, -XX:MaxRAMPercentage=66.0 (lowered from jaz's ~72% for more native headroom; fixed native costs — ~600 thread stacks, metaspace, code cache — are roughly constant and dominate small 4GB containers) - -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:G1PeriodicGCInterval=10000 - -XX:+UseCompactObjectHeaders (JEP 519, ~5-15% heap savings; jaz never sets it) Off-heap diagnostics (workloads run 4GB-30GB containers, OOM-killed by native/RSS growth of unknown origin): - -XX:NativeMemoryTracking=summary — jcmd VM.native_memory summary[.diff] to attribute JVM-internal native memory (metaspace, threads, code cache, direct buffers) - -Djdk.nio.maxCachedBufferSize=262144 — bound the JDK's unbounded per-thread temp direct-buffer cache (a common RSS balloon with many I/O threads) - Dynamic -XX:MaxDirectMemorySize derived from the cgroup limit (DOT_DIRECT_MEM_PCT%, default 20%, clamped [512m,4096m]; fail-safe to unset when unbounded). Caps ONLY NIO direct ByteBuffers — a rule-in/rule-out probe, not a catch-all (does not bound JNI/ mmap/Unsafe/Netty); use NMT + jemalloc profiling for those. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… of Java 25 PR Keep #35914 focused on the Java 25 migration only. The compact object headers (-XX:+UseCompactObjectHeaders), G1/heap tuning, and off-heap OOM diagnostics (NativeMemoryTracking, jdk.nio.maxCachedBufferSize, dynamic MaxDirectMemorySize) move to a dedicated branch (issue-33865-java25-memory-tuning) since they are runtime tuning, not the migration itself — and COH is what required the CacheSizingUtil changes. setenv.sh: restore original (ZGC) container config, add only --enable-preview (required at runtime to load preview-compiled classes, e.g. java.lang.StableValue / JEP 502). parent/pom.xml: drop -XX:+UseCompactObjectHeaders from the surefire/failsafe argLine; keep --enable-preview. This removes the CacheSizingUtilTest object-size failure that fail-fast canceled the PR test matrix. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stacked on the Java 25 migration (#35914). Runtime memory tuning + diagnostics that were split out of that PR: - -XX:+UseCompactObjectHeaders (JEP 519, ~5-15% heap savings; jaz never sets it) - Switch container GC ZGC -> G1 with jaz-mirrored tuning (MinHeapFreeRatio=10, MaxHeapFreeRatio=50, G1PeriodicGCInterval=10000) and MaxRAMPercentage=68 - Off-heap OOM diagnostics: -XX:NativeMemoryTracking=summary, -Djdk.nio.maxCachedBufferSize=262144, and a dynamic cgroup-derived -XX:MaxDirectMemorySize (rule-in/rule-out probe for direct ByteBuffers) - surefire/failsafe argLine: add -XX:+UseCompactObjectHeaders (prod parity) - CacheSizingUtilTest: layout-agnostic assertions (COH shrinks object headers 12->8; the util reads live Unsafe offsets so it adapts — only the hardcoded expectations were wrong) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
3 tasks
…t-enable unit tests
Replace CacheSizingUtil's manual Unsafe/header math with the authoritative
Instrumentation.getObjectSize() for shallow size (recursion for retained size kept).
getObjectSize is exact under compact object headers, compressed oops, and alignment —
no header/oops guesswork.
- Instrumentation is read ONLY via ByteBuddyAgent.getInstrumentation() (already-installed
agent); never install() — its self-attach hangs on JDK 21+ in containers. Falls back to
the Unsafe estimate when no agent is present.
- Fix latent Unsafe-fallback bug: sizeof() used f.getClass() (always Field.class) instead of
f.getType(), under-counting when the highest-offset field is a long/double.
- Agent-enable dotcms-core unit tests: dependency-plugin 'properties' goal populates
${net.bytebuddy:byte-buddy-agent:jar}; a module-scoped ${bytebuddy.agent.argline} (empty
elsewhere) preloads it via -javaagent in the shared surefire/failsafe argLine, so the
getObjectSize path is exercised in CI. Verified: agent-presence test runs (not skipped).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… small containers With MaxRAMPercentage=72, a 1GB container allocates ~737MB to heap, leaving only ~287MB for metaspace, stack, code cache, and direct buffers. The 512MB floor caused OOM kills on containers under ~2.5GB; 128MB fits comfortably within that budget. https://claude.ai/code/session_015P4qyq2daq4w7WeYhbs1gw
Removed detailed comments about jaz JVM launcher and tuning flags.
The -z check enabled jaz when the variable was unset (the default), which is the opposite of the documented intent. Change to -n so jaz is only activated when JAZ_IGNORE_USER_TUNING=1 is explicitly set. https://claude.ai/code/session_01HDzAEtJb7E3KmM2SKRs9Gn
…BASE This flag was present in the original JAVA_OPTS_BASE and was accidentally dropped during the Java 25 memory tuning refactor. https://claude.ai/code/session_01Au82uqQdNaYjAuQanj2rdB
Contributor
|
Claude finished @wezell's task in 1m 44s —— View job Rollback Safety Analysis
Result: ✅ Safe To Rollback All 5 changed files were analyzed against the rollback-unsafe categories:
No matches against any unsafe category (C-1 through M-4):
Label |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Big news in this PR - this turns on Java's new
UseCompactObjectHeaderswhich can save up to 20% in memory usage across the board. With this change, we had to adjust the dotCMS's default cache sizing algo and tests to account for the smaller objects.It also applies jaz's recommended GC tuning suggestions and adds some constraints for off-heap memory allocations by default ( we have been running unbounded) while also removing jaz as the default java launcher. jaz can be re-enabled by setting the env var
JAZ_IGNORE_USER_TUNING=1Container JVM (
setenv.sh)-XX:+UseCompactObjectHeaders(JEP 519, product flag on JDK 25; ~5–15% heap savings; jaz does not set it — verified viaJAZ_DRY_RUN)MinHeapFreeRatio=10,MaxHeapFreeRatio=50,G1PeriodicGCInterval=10000),MaxRAMPercentage=68-XX:NativeMemoryTracking=summary,-Djdk.nio.maxCachedBufferSize=262144, and a dynamic, cgroup-derived-XX:MaxDirectMemorySize(20% clamped[512m,4096m], fail-safe, env-overridable)Tests
-XX:+UseCompactObjectHeaders(prod parity)CacheSizingUtilTest: layout-agnostic assertions (COH shrinks headers 12→8B; the util reads liveUnsafeoffsets and adapts — only the hardcoded byte expectations were wrong)TODO (next commit)
CacheSizingUtilto useInstrumentation.getObjectSize()(authoritative shallow size;Unsafefallback when no agent) per discussion.This PR fixes: #33865