Why Java Apps OOM in Kubernetes Even Below Xmx and How to Fix It
This article explains why Java applications running in Kubernetes can encounter Out‑Of‑Memory errors despite heap usage staying under the Xmx limit, by examining container resource limits, JVM memory models, cgroup behavior, and provides practical configuration recommendations to prevent OOM.
Background
Java has been a dominant language for over two decades thanks to its vibrant open‑source community and rich ecosystem. In the cloud‑native era, enterprises migrate workloads to Kubernetes to leverage cloud computing benefits, but Java’s runtime model clashes with container resource constraints, leading to costly memory consumption and frequent OOM incidents.
Kubernetes Resource Configuration
Kubernetes defines two memory parameters for a container: requests (guaranteed amount) and limits (maximum allowed). If a container exceeds its limit, the kubelet kills it with an OOM event.
spec:
containers:
- name: edas
image: alibaba/edas
resources:
requests:
memory: "1024Mi"
limits:
memory: "4096Mi"
command: ["java", "-jar", "edas.jar"]Container OOM
Containers run as sandboxed processes using Linux namespaces and cgroups. When a process’s memory usage surpasses the cgroup memory.limit_in_bytes, the kernel’s OOM Killer terminates the process. The two key cgroup files are:
# Current container memory limit
cat /sys/fs/cgroup/memory/memory.limit_in_bytes
4294967296
# Current container memory usage
cat /sys/fs/cgroup/memory/memory.usage_in_bytes
39215104JVM OOM Types
java.lang.OutOfMemoryError: Java heap space – heap exhausted, usually due to leaks or insufficient -Xmx.
java.lang.OutOfMemoryError: Metaspace/PermGen – class metadata overflow; adjust -XX:MaxMetaspaceSize or -XX:MaxPermSize.
java.lang.OutOfMemoryError: Unable to create new native thread – native memory or thread limits reached; tune ulimit, thread pool size, or stack size.
OS vs JVM Memory Mapping
The JVM runs as a native C++ process on Linux, sharing the OS virtual address space. Key segments include:
Code segment – JVM’s own executable code.
Data segment – JVM internal data.
Heap – Java objects; a logical space built on top of the process heap.
Stack – native stack for the JVM process (not the Java thread stack).
Non‑Heap Memory & Native Memory Tracking (NMT)
Beyond the heap, the JVM uses non‑heap memory (direct buffers, JNI allocations, etc.). NMT, enabled with -XX:NativeMemoryTracking=summary|detail, reports memory reserved and committed by each JVM component.
$ java -Xms300m -Xmx300m -XX:+UseG1GC -XX:NativeMemoryTracking=summary -jar app.jarSample NMT output:
Native Memory Tracking:
Total: reserved=1764MB, committed=534MBBreakdown (example):
Java Heap (reserved=300MB, committed=300MB)
Metaspace (reserved=1078MB, committed=61MB)
Thread (reserved=60MB, committed=60MB)
Code Cache (reserved=250MB, committed=36MB)
GC (reserved=47MB, committed=47MB)
Symbol (reserved=15MB, committed=15MB)Configuration Recommendations
Use a container‑aware JDK (8u191+, 9+, 10+, or 8u372+ for Cgroup v2) so the JVM respects cgroup limits.
Enable NMT during testing to understand JVM memory distribution; query with jcmd <pid> VM.native_memory summary scale=MB.
Set container memory limit about 20‑30% higher than the JVM’s observed total memory (heap + non‑heap) to provide a safety margin.
Configure automatic heap dumps on OOM and persist them (e.g., PVC, OSS, NAS) for post‑mortem analysis.
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.
Alibaba Cloud Native
We publish cloud-native tech news, curate in-depth content, host regular events and live streams, and share Alibaba product and user case studies. Join us to explore and share the cloud-native insights you need.
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.
