Boost Java Cloud Run Performance: Proven JVM and Container Optimizations
Learn how to accelerate Java applications on Google Cloud Run by minimizing container image size, leveraging container-aware JVM settings, reducing thread usage, and applying Spring Boot-specific tweaks such as layered JARs, lazy initialization, and avoiding background tasks to cut startup latency and memory consumption.
Translator Note
This article originally describes Java optimization in Google Cloud Run; most recommendations also apply to Docker and Kubernetes containers.
Introduction
The guide presents Google’s recommendations for optimizing Java‑based Cloud Run services, especially Spring Boot, complementing the general optimization tips that also work for traditional Java applications.
Traditional Java web application optimization aims for high concurrency, low latency, and long‑running stability, with the JVM’s JIT and hotspot compilation improving efficiency.
Typical best practices include handling concurrent requests (thread‑based I/O or non‑blocking I/O) and using connection pools or background tasks to reduce response latency.
Many of these practices suit long‑running services but may be less effective for Cloud Run, which only runs while handling requests. The following sections cover Cloud Run‑specific trade‑offs for reducing startup time and memory usage.
Optimizing the Container Image
Reducing image size shortens load and startup times. Recommended actions:
Minimize the container image size.
Avoid using “fat” JARs that bundle dependencies.
Build images with Jib.
Minimize Image Size
Ensure the image does not contain source code, Maven build artifacts, build tools, Git directories, or unused binaries.
Consider using the Distroless Java base image, which is the default when building with Jib.
If you build from a Dockerfile, use multi‑stage builds so the final image contains only the JRE and the application JAR.
Avoid Fat JARs
Frameworks like Spring Boot create an “uber” JAR that must be unpacked at startup, slowing Cloud Run. Use Jib to create a slim JAR, or Spring Boot 2.3’s layered JAR feature.
Use Jib
The Jib plugin can produce minimal containers and automatically unpack dependencies. It supports Maven and Gradle and offers out‑of‑the‑box support for Spring Boot.
JVM Optimizations
Optimizing the JVM improves performance and memory usage.
Use a Container‑Aware JVM
Older JDKs read CPU and memory limits from
/proc, which can cause thread‑pool oversizing and heap sizes that exceed container limits. Use a container‑aware JVM (OpenJDK 8u192 or newer) that reads limits from
/proc/cgroups.
Understand JVM Memory Usage
JVM memory consists of native memory and heap memory. On a 256 MiB Cloud Run instance, not all memory can be allocated to the heap because the JVM and OS need native memory. Enable Native Memory Tracking to inspect usage on OOM events.
<code>java -XX:NativeMemoryTracking=summary \
-XX:+UnlockDiagnosticVMOptions \
-XX:+PrintNMTStatistics \
...</code>Use a Java memory calculator or Alibaba’s Arthas to estimate native memory requirements.
Disable Optimizing Compiler
For short‑lived serverless workloads, consider disabling tiered compilation to reduce startup time:
<code>JAVA_TOOL_OPTIONS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1"</code>Disable Class Verification
If you trust the container image, you can disable verification to speed up startup:
<code>JAVA_TOOL_OPTIONS="-noverify"</code>Note: This option is deprecated in OpenJDK 13+.
Reduce Thread Stack Size
Each Java thread consumes native memory (default 1 MiB). Reduce the stack size to lower memory usage, e.g.:
<code>JAVA_TOOL_OPTIONS="-Xss256k"</code>Reduce Threads
Use non‑blocking reactive programming and avoid unnecessary background tasks to lower memory consumption.
Limit Thread Count
Cloud Run allows up to 80 concurrent requests. Configure the maximum threads, for example in Spring Boot:
<code>server.tomcat.max-threads=80</code>Adopt Reactive Programming
Reactive frameworks (Spring WebFlux, Micronaut, Quarkus) can handle many concurrent requests with far fewer threads. Avoid writing blocking code in a reactive application.
Avoid Background Activities
When an instance receives no requests, Cloud Run limits CPU. Background tasks such as JDBC pool cleanup, metric batching, @Async methods, or message listeners may not run, leading to degraded behavior.
Application Optimizations
Reduce startup tasks and use connection pools wisely. For low QPS, consider opening and closing connections per request; for high QPS, ensure the total connections across instances stay within database limits.
Using Spring Boot
Prefer Spring Boot 2.2+ for built‑in startup improvements. Enable lazy initialization to defer bean creation:
<code>spring.main.lazy-initialization=true</code>Or set the environment variable:
<code>SPRING_MAIN_LAZY_INITIATIALIZATION=true</code>Avoid classpath scanning overhead by using the Spring Context Indexer:
<code><dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<optional>true</optional>
</dependency>
</code>Do not package Spring Boot Devtools in production images; exclude or disable it.
Next Steps
For more tips, see the referenced articles on efficient Java optimization and migrating existing services.
References
General optimization tips: https://cloud.google.com/run/docs/tips
Minimize container image: https://cloud.google.com/run/docs/tips#minimize-container
Distroless Java base: https://github.com/GoogleContainerTools/distroless/tree/master/java
Jib plugin: https://cloud.google.com/java/getting-started/jib
Spring Boot 2.3 layered JAR: https://juejin.im/post/6844904167710916615
Jib GitHub: https://github.com/GoogleContainerTools/jib
Java memory calculator: https://github.com/cloudfoundry/java-buildpack-memory-calculator
Arthas: https://alibaba.github.io/arthas/
OpenJDK 13 deprecation note: https://www.oracle.com/java/technologies/javase/13all-relnotes.html
CPU limit on Cloud Run: https://cloud.google.com/run/docs/reference/container-contract#cpu-request
Avoid background tasks: https://cloud.google.com/run/docs/tips/java#background
Configure max instances: https://cloud.google.com/run/docs/configuring/max-instances
Manual Spring Boot optimizations: https://spring.io/blog/2018/12/12/how-fast-is-spring
Spring Boot Devtools: https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-devtools
Disable Spring Boot Devtools: https://docs.spring.io/spring-boot/docs/current/reference/html/using-spring-boot.html#using-boot-devtools
General Java optimization: https://cloud.google.com/run/docs/tips/general
Migrating services: https://cloud.google.com/run/docs/migrating
Original article: https://cloud.google.com/run/docs/tips/java#appcds
Java Architecture Diary
Committed to sharing original, high‑quality technical articles; no fluff or promotional content.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.