Why Your Java App Gets OOMKilled in Kubernetes and How to Fix It
This article explains why Java applications running in Kubernetes containers are often terminated with OOMKilled (exit code 137), analyzes the underlying JVM memory‑limit mismatches, and provides practical solutions using cgroup‑aware JVM flags and memory‑tuning techniques.
In everyday work we often deploy applications with Kubernetes, but issues like the JVM heap being smaller than the Docker container memory and still being OOMKilled can occur. This article introduces the meaning of Kubernetes OOMKilled exit code 137.
Exit Code 137
Indicates the container received a SIGKILL signal (kill -9), which can be triggered by the user or Docker daemon.
Common when the pod's memory limit is too low, causing OOMKilled; the state shows "OOMKilled": true and OOM logs appear in dmesg.
Root Cause Analysis
Problems often arise with JDK 8u131 or later when running JVM inside containers: the JVM defaults to using the host node's memory for native VM space (heap, direct memory, stack) instead of the container's limits.
Example command output shows a contradiction:
docker run -m 100MB openjdk:8u121 java -XshowSettings:vm -version
VM settings:
Max. Heap Size (Estimated): 444.50M
Ergonomics Machine Class: server
Using VM: OpenJDK 64-Bit Server VMAlthough the container memory is limited to 100 MB, the JVM reports a maximum heap of 444 MB, which can cause the node to kill the JVM.
Solution
JVM Detects cgroup Limits
Enable the flags -XX:+UnlockExperimentalVMOptions and -XX:+UseCGroupMemoryLimitForHeap so the JVM automatically senses Docker cgroup limits and adjusts the heap size dynamically.
Note: If -Xmx is also set, it overrides the -XX:+UseCGroupMemoryLimitForHeap flag.
Summary:
The flag -XX:+UseCGroupMemoryLimitForHeap lets the JVM detect the container's maximum heap.
The -Xmx flag sets a fixed maximum heap size.
Besides the heap, non‑heap memory also consumes container memory.
Trying Container‑Aware Mechanism with JDK 9
docker run -m 100MB openjdk:8u131 java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XshowSettings:vm -versionResult shows heap size 44.5 M.
docker run -m 1GB openjdk:8u131 java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XshowSettings:vm -versionResult shows heap size 228 M.
docker run -m 1GB openjdk:8u131 java \
-XX:+UnlockExperimentalVMOptions \
-XX:+UseCGroupMemoryLimitForHeap \
-XX:MaxRAMFraction=1 -XshowSettings:vm -versionResult shows heap size 910.5 M, demonstrating that -XX:MaxRAMFraction=1 can allocate almost all available memory to the heap.
Analysis of Off‑Heap Memory
Beyond the heap, Java uses off‑heap (direct) memory, typically via Unsafe or DirectByteBuffer. This off‑heap space can become a hidden source of memory consumption.
JVM Parameter MaxDirectMemorySize
The flag -XX:MaxDirectMemorySize limits the size of NIO direct‑buffer allocations. If not specified, its default is the same as -Xmx (or the runtime max memory). -XX:MaxDirectMemorySize When the flag is omitted, the JVM sets the limit to Runtime.getRuntime().maxMemory().
if (s == null || s.isEmpty() || s.equals("-1")) {
directMemory = Runtime.getRuntime().maxMemory();
} else {
long l = Long.parseLong(s);
if (l > -1) directMemory = l;
}The maxDirectMemory() method then returns this value.
Conclusion
If MaxDirectMemorySize is not explicitly configured, the usable NIO direct memory equals -Xmx minus a survivor space, so the total heap + direct memory can approach double the configured -Xmx value.
Other Ways to Retrieve maxDirectMemory
Use BufferPoolMXBean or java.nio.BufferPool via SharedSecrets:
public BufferPoolMXBean getDirectBufferPoolMBean() {
return ManagementFactory.getPlatformMXBeans(BufferPoolMXBean.class)
.stream()
.filter(e -> e.getName().equals("direct"))
.findFirst()
.orElseThrow();
}Memory Analysis Issues
Using -XX:+DisableExplicitGC disables explicit System.gc() calls, which can prevent reclamation of old‑generation direct buffers, potentially leading to out‑of‑memory situations.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Open Source Linux
Focused on sharing Linux/Unix content, covering fundamentals, system development, network programming, automation/operations, cloud computing, and related professional knowledge.
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.
