JDK Version-Currency Programme
A policy for how many releases behind current any service may be, the calendar that follows from Oracle's and OpenJDK's six-month releases and two-year LTS cadence, and the CI check that catches breakage early.
Java Consulting
Last reviewed by Tyler Eastridge
AceMQ delivers Java consulting services with partner Java specialists, aimed at the runtime rather than the application: a JDK version-currency programme so no service falls years behind, upgrade plans between LTS releases, container memory and CPU sizing, and garbage collector choice backed by measurement. It does not change your application code, ship a JDK or advise on licences. Every engagement starts with a written plan.
Is This You?
Nobody can say which JDK version each service runs, and the answer changes every quarter
An 8 to 17 upgrade has stalled on a library, an agent or an application server nobody owns
Every March and September someone proposes a Java upgrade and it loses to feature work
Pods restart with exit code 137 after a base image change and the heap was never full
Heap and GC flags were copied from a blog post in 2019 and nobody knows if they still apply
CI builds on one JDK and production runs on another
You need an outside opinion before a platform team will fund the work
Outcomes
Concrete state changes, not deliverable counts. This is what actually differs about your Java estate when the engagement closes.
Before
Java upgrades happen when a vendor forces them, one emergency at a time.
A written upgrade calendar: a policy for how far behind current any service may be, an owner, and a place in the release train.
Before
The 8 to 17 move is described as a weekend and has no list of what will break.
A scan-backed list of blockers per service, libraries and agents first, ranked by how many services each one blocks.
Before
Memory settings are guesses, so the same service is OOMKilled in one cluster and idle in another.
Heap, native memory and container limits sized from measurement, with headroom stated, and a sizing rule new services inherit.
Before
GC flags are folklore.
A collector chosen on stated criteria and tested against your workload, or the default left alone with the reason written down.
Scope
A policy for how many releases behind current any service may be, the calendar that follows from Oracle's and OpenJDK's six-month releases and two-year LTS cadence, and the CI check that catches breakage early.
Service-by-service plans for moving between LTS releases, such as 8 to 17, 17 to 21 and 21 to 25, with the order, the test plan and a rollback for each wave.
What stands in the way of moving legacy Java services forward: libraries that need a newer release, bytecode agents, build plugins and application servers, found with the dependency and deprecation scanners in the JDK and ranked by impact.
Heap against the Docker or Kubernetes container limit, then metaspace, thread stacks, code cache and direct buffers on top, CPU limits against thread pools, and the exit 137 post-mortem.
G1, ZGC or another collector chosen from your latency and throughput requirements, and performance optimization tested on your Java applications, with flags kept only where measurement supports them.
One reference base image per LTS, JDK version pinned in builds, tests run on the target release, and a nightly job against the newest release.
The fixed-scope review that finds the first problem: JDK versions, memory and GC settings, truststores and TLS, with a written report ranked by production risk.
Runbooks, a sizing guide and working sessions with your platform team, so the programme outlasts the engagement.
The Engagement
Every phase has a defined duration and a concrete artifact handed over at the end of it. You always know what stage you're in and what you've received.
What runs where: JDK release and build per service, how it is packaged, the frameworks and agents on top, and what the memory limits are. Written findings, ranked by risk, before anything changes.
You receive
The version-currency policy, the target release per service, the sizing rule for containers and the order of waves, each with a rollback.
You receive
Low-risk services first on the new release, with the change rehearsed on a copy of production settings. Each wave ends with measured memory and start-up behaviour, not an assumption.
You receive
AceMQ and your platform team hand over the calendar, the CI canary, the base images and the sizing guide, with optional 24/7 support for the Java layer afterwards.
You receive
Java ships a feature release every March and September, and Oracle's roadmap marks 8, 11, 17, 21 and 25 as LTS releases, with the next planned LTS being Java 29 in September 2027. Oracle notes that LTS designation and dates are subject to change. A service that jumps from one LTS to the next crosses two years of change in one move, and one that stays on Java 8 crosses more than a decade of it.
A currency programme turns that into a policy the organization can keep. It is not a rule that everything runs the newest release. It is a rule for how far behind any service may fall, who checks, and what happens when one breaches it.
| Decision | Typical options | What the policy writes down |
|---|---|---|
| How far behind | Current LTS, or one LTS back | The maximum gap, and who may grant an exception |
| Who owns the calendar | Platform team, or each service team | A named owner and a date for each LTS decision |
| How breakage is caught early | Nightly build against the newest release | Which services run the canary and who reads the result |
| What base images exist | One reference image per LTS | Where images are built and how stray ones are found |
| What happens to a laggard | Plan with a date, or a recorded exception | The review that stops exceptions living forever |
Rule we hold
Change the JDK and nothing else in a window. A platform change, a framework upgrade and a JDK upgrade are three changes with three rollbacks, so a failure points at one cause.
The 8 to 17 upgrade stalls for the same reasons in most estates. The breaks are documented in the OpenJDK enhancement proposals, so the work is finding which of them your services hit, not discovering them in production.
| Release | What changed | Who feels it |
|---|---|---|
| Java 11 | Java EE and CORBA modules removed (JEP 320), including JAXB and JAX-WS | Services that used them from the JDK now need explicit dependencies |
| Java 15 | Nashorn JavaScript engine removed (JEP 372) | Anything that evaluated scripts through the JDK |
| Java 17 | JDK internals strongly encapsulated (JEP 403); the single relaxation flag from 9 to 16 is gone | Libraries and agents that reach into internal classes by reflection |
| Upgrades to 17 and later | Default charset: Oracle's JDK 21 migration guide flags it | Services that read or write files without naming an encoding |
| Java 24 | Security Manager permanently disabled (JEP 486) | Sandboxing designs that relied on it |
| Java 25 | 32-bit x86 port removed (JEP 503) | Rare: 32-bit x86 builds |
Frameworks set their own floor. Spring Boot 3 needs Java 17, Spring Boot 4.1 needs Java 17 or later and runs up to Java 27, and Apache Kafka 4.0 brokers need Java 17, so one old service can pin a whole platform. Moving straight from 8 to 21 or 25 is one migration instead of two, but only if every library on the path supports it.
The JDK ships scanners for this work. jdeps lists a service's dependencies and its use of JDK internals, and jdeprscan finds uses of deprecated APIs. We run them across the estate, join the results to the build files, and rank blockers by how many services each one stops.
The JVM detects container limits by default, and its default maximum heap is a quarter of the container's memory. Teams raise that with -Xmx or -XX:MaxRAMPercentage until the heap alone nearly fills the limit, and then a new JDK or base image tips the process over.
| Symptom | Likely cause | What we check |
|---|---|---|
| Exit code 137, no OutOfMemoryError | Total process memory passed the container limit while the heap had room | Native Memory Tracking in summary mode, then heap, metaspace, thread stacks, code cache and direct buffers |
| Slow start after a limit change | Thread pools and GC threads sized from the wrong processor count | How many CPUs the JVM sees, and ActiveProcessorCount where a limit needs it |
| Long pauses after an upgrade | A different default collector or heap shape | GC logs on the old and new release under real load |
| Heap steady, memory climbing | Growth outside the heap | Direct buffers, native libraries and class loading |
Collector choice follows the requirement, not fashion. G1 has been the default since Java 9. ZGC gained a generational mode in Java 21, made it the default in Java 23 and dropped the non-generational mode in Java 24, which changes what a ZGC flag set means. We choose from your latency and throughput needs, test with your workload and leave the default alone when it is enough. We state no heap sizes or pause targets until we have measured them.
What we do not do
We do not copy tuning flags between services, and we do not promise performance gains from a release. Gains are measured on your workload, in the pilot.
Typical engagements
Typical engagement scenarios: what the work covers and what it delivers. They describe the service, not past results.
Mid-Sized Distribution Company
A typical engagement for a company that wants to leave an Oracle Java SE subscription or avoid one: inventory every Java runtime, compare OpenJDK distributions against the estate, and write the migration plan.
SaaS Platform Team
A typical engagement for Java services that restart with exit code 137 after a base image brings a newer JDK: the heap is not full, no OutOfMemoryError appears, and the memory that matters lives outside the heap.
SaaS Observability Vendor
Ongoing 24/7 support for an Elasticsearch estate suffering repeated parent circuit breaker trips and long garbage collection pauses under aggregation load.
Global Payments Processor
Assessment of APM instrumentation coverage and trace completeness across a service estate where distributed traces kept breaking at service boundaries.
Digital Commerce Platform
Remediation of application latency and memory growth traced to APM agent configuration on the customer's own JVM and container estate.
Insurance Services Provider
Ongoing support for distributed tracing across a mixed New Relic and OpenTelemetry estate where traces broke at instrumentation boundaries.
Global Payments Processor
Assessment of which services, dependencies, and code paths are genuinely covered by APM instrumentation versus assumed to be.
Enterprise Technology Organizations
A structured review of GemFire region design, WAN topology, JVM tuning and security configuration, producing a risk-prioritized roadmap before problems reach production.
FAQ
A JDK version-currency programme, upgrade planning between LTS releases, blocker analysis across your libraries and agents, container memory and CPU sizing, and garbage collector selection backed by measurement. It is delivered by AceMQ engineers with partner Java specialists, and every project starts with a written plan. It covers the runtime and its surroundings, not application code, and AceMQ ships no JDK.
With a policy and a calendar, not heroics. Decide the maximum gap, give the calendar an owner, run a nightly build against the newest release to catch breakage early, and keep one reference base image per LTS. Oracle's roadmap lists Java 25 as the current LTS and Java 29 as the next planned LTS in September 2027, dates subject to change. AceMQ writes the policy, scans the estate and runs the first waves with your platform team.
Usually on one of three things: a library or agent that reaches into JDK internals, which Java 17 strongly encapsulates; code that relied on the Java EE modules removed in Java 11; or a framework or application server that has not moved. The JDK's own jdeps and jdeprscan tools find most of them. We rank blockers by how many services each one stops, so the first fix unblocks the most.
It depends on the service, not a single answer. Java 25 is the current LTS, and Java 17 and 21 remain LTS releases, with Spring Boot 3 and Kafka 4.0 brokers requiring at least Java 17. The plan sets a target per service from its frameworks, its libraries and the cost of a second migration later. Distribution choice and licensing are covered on the Java page.
No to both. AceMQ plans and supports the runtime, and your developers change the code. Licensing and distribution questions are for your own agreements and counsel; AceMQ supplies the technical inventory they work from.
Let's talk
Tell us which JDK releases you run, how they are packaged and where the upgrades have stalled. We reply within 1 hour and follow with a written scope.
Send us a message and we'll follow up within 1 hour — or book a free 30-min consultation directly.
305-204-2607info@acemq.comPrefer to talk now? Call us directly or use the consultation tab to find a time that works.