Java 10 introduced new container-aware JVM features that greatly improve how Java applications run in Docker environments. These features provide enhanced automatic detection and utilization of container-based limits for memory and CPU resources, allowing Java applications to respect the constraints of containers better.
Here’s a step-by-step guide to using the container-aware JVM features in Java 10 for Docker:
1. Understand the Features
Before Java 10, the JVM didn’t recognize container resource limits (like those set by Docker). With Java 10, the JVM can now:
- Detect container memory limits (e.g.,
--memory
or-m
in Docker). - Detect container CPU limits (e.g.,
--cpus
in Docker). - Adjust garbage collection (GC) behavior based on allocated container resources.
2. Key JVM Options
Java 10 enables container awareness by default, but you can check and fine-tune these settings using certain JVM options:
-XX:MaxRAMPercentage
Allows you to define the maximum available heap memory as a percentage of the container’s total memory limit (default: 25%).-
-XX:InitialRAMPercentage
Sets the initial heap size as a percentage of the container’s memory limit. -
-XX:MinRAMPercentage
Specifies the minimum heap size as a percentage of the container’s memory. -
-XX:ActiveProcessorCount
Lets you manually define the number of CPUs the JVM should consider if it doesn’t automatically detect container limits or you want to override them.
3. Check Container-Aware JVM Behavior
You can check if the JVM recognizes the container limits by running a simple Java program inside a Docker container. Below is an example:
Java Code:
public class ContainerAwarenessTest {
public static void main(String[] args) {
System.out.println("Available processors: " + Runtime.getRuntime().availableProcessors());
System.out.println("Max memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024 + " MB");
}
}
4. Test in Docker
- Write a Dockerfile
Create aDockerfile
using a Java 10 JDK image for testing:FROM openjdk:10-jdk COPY ContainerAwarenessTest.java /usr/src/myapp/ WORKDIR /usr/src/myapp RUN javac ContainerAwarenessTest.java CMD ["java", "ContainerAwarenessTest"]
- Build and Run the Docker Container
- Build the Docker image:
docker build -t java-container-awareness .
- Run the container with memory and CPU limits:
docker run --memory="512m" --cpus="1" java-container-awareness
- Expected Output
- The
Runtime.getRuntime().maxMemory()
will show 512 MB or close to it. - The
Runtime.getRuntime().availableProcessors()
will report 1 processor.
- The
5. Fine-Tune with JVM Options
To customize the JVM’s behavior further using Java 10’s new options, add the JVM options with the java
command. For example:
docker run --memory="1g" --cpus="2" java-container-awareness java \
-XX:MaxRAMPercentage=50.0 \
-XX:InitialRAMPercentage=25.0 \
-XX:ActiveProcessorCount=1 \
ContainerAwarenessTest
This manually adjusts:
- The maximum heap to 50% of the container memory limit (1 GB).
- The initial heap to 25% of the container memory limit.
- The active processor count to override to only 1.
6. Verify
For detailed resource information, you can also enable verbose GC logging to monitor heap and memory usage in real-time:
docker run --memory="512m" --cpus="1" java-container-awareness java \
-Xlog:gc \
ContainerAwarenessTest
7. Move Beyond Java 10 [Optional]
If you’re using newer Java versions (like Java 11 or later), these container-aware features are still present, and additional enhancements have been made to how Java applications behave in containers. Make sure your base image and application are updated as needed.
By using these container-aware JVM features, your Java applications will better respect container resource constraints, leading to improved efficiency and performance in Dockerized environments.