Containerize your Java applications
This article provides an overview of recommended strategies and settings for containerizing Java applications.
When you're containerizing a Java application, carefully consider how much CPU time the container will have available. Then consider how much memory will be available both in terms of total amount of memory, and the heap size of the Java Virtual Machine (JVM). In containerized environments, applications may have access to all processors and therefore be able to run multiple threads in parallel. It's common, though, that containers have a CPU quota applied that may throttle access to CPUs.
The JVM has heuristics to determine the number of "available processors" based on CPU quota, which can dramatically influence the performance of Java applications. The memory allocated to the container itself and the size of the heap area for the JVM are as important as the processors. These factors will determine the behavior of the garbage collector (GC) and the overall performance of the system.
Containerize a new application
When you're containerizing a Java workload for a new application, you have to take two things into account when thinking about memory:
- The memory allocated to the container itself.
- The amount of memory available to the Java process.
Understand JVM default ergonomics
Applications need a starting point and settings. The JVM has default ergonomics with pre-defined values that are based on number of available processors and amount of memory in the system. The default values shown in the following tables are used when the JVM is started without specific startup flags or parameters.
The following table shows the default GC used for the resources available:
|Resources available||Default GC|
|Any number of processors
Up to 1791 MB of memory
1792 MB or more of memory
The following table shows the default initial heap size for the type of environment:
|Type of environment||Default initial heap size|
|Containers||1/4 of available memory|
|Non-container||1/64 of available memory|
These values are valid for OpenJDK 11 and later, and for most distributions, including Microsoft Build of OpenJDK, Azul Zulu, Eclipse Temurin, Oracle OpenJDK, and others.
Determine container memory
Pick a container memory amount that will serve your work load best, depending on the needs of your application and its distinctive usage patterns. For example, if your application creates large object graphs, then you'll probably need more memory than you'd need for applications with many small object graphs.
If you don't know how much memory to allocate, a good starting point is 4 GB.
Determine JVM heap memory
When you allocate JVM heap memory, be aware that the JVM needs more memory than just what is used for the JVM heap. When you set the maximum JVM heap memory, it should never be equal to the amount of container memory because that will cause container Out of Memory (OOM) errors and container crashes.
Allocate 75% of container memory for the JVM heap.
On OpenJDK 11 and later, you can set the JVM heap size in the following ways:
Determine which GC to use
Previously, you determined the amount of JVM heap memory to start with. The next step is to choose your GC. The amount of maximum JVM heap memory you have is often a factor in choosing your GC. The following table describes the characteristics of each GC.
|Number of cores||1||2||2||2||2|
|Java Heap size||<4 GBytes||<4 GBytes||>4 GBytes||>28 GBytes||>4 GBytes|
|Pause||Yes||Yes||Yes||Yes (<1 ms)||Yes (<10 ms)|
|JDK version||All||All||JDK 8+||JDK 17+||JDK 11+|
|Best for||Single core small heaps||Multi-core small heaps or batch workloads with any heap size||Responsive in medium to large heaps (request-response/DB interactions)||Responsive in medium to large heaps (request-response/DB interactions)||Responsive in medium to large heaps (request-response/DB interactions)|
For most general-purpose microservice applications, start with the Parallel GC.
Determine how many CPU cores are needed
For any GC other than SerialGC, we recommend two or more vCPU cores. We don't recommend selecting anything less than 1 vCPU core on containerized environments.
If you don't know how many cores to start with, a good choice is 2 vCPU cores.
Pick a starting point
We recommend starting with two replicas or instances in container orchestration environments like Kubernetes, OpenShift, Azure Spring Cloud, Azure Container Apps, and Azure App Service. The following table summarizes the recommended starting points for the containerization of your new Java application.
|vCPU cores||Container memory||JVM heap size||GC||Replicas|
The JVM parameters to use are:
Containerize an existing (on premises) application
If your application is already running on premises or on a VM in the cloud, then we recommend that you start with:
- The same amount of memory that the application currently has access to.
- The same number of CPUs (vCPU cores) the application currently has available.
- The same JVM parameters that you currently use.
If the vCPU cores and/or container memory combination isn't available, then pick the closest one, rounding up the vCPU cores and container memory.
Now that you understand the general recommendations for containerizing Java applications, continue on to the following article to establish a containerization baseline:
Submit and view feedback for