Cloud Native 20 min read

Combining JVM Heap and Kubernetes Memory Requests/Limits to Avoid Out‑Of‑Memory Issues

This article explains how JVM heap, metaspace, and other non‑heap memory interact with Kubernetes pod memory requests and limits, demonstrates practical experiments with different heap sizes, and provides guidelines for configuring container‑aware JVM flags and pod resources to prevent crashes and evictions.

System Architect Go
System Architect Go
System Architect Go
Combining JVM Heap and Kubernetes Memory Requests/Limits to Avoid Out‑Of‑Memory Issues

Introduction : Running Java applications in containers requires understanding both the JVM memory model and Kubernetes memory management; mis‑configuration can cause infrastructure overspend or application crashes.

JVM Memory Model Overview : The JVM consists of Heap and Metaspace (non‑heap). Metaspace stores class metadata and grows as needed, while the Heap holds object instances and is the primary target of garbage collection. A simple Kotlin program repeatedly creates large ByteArray objects to fill the heap.

val list = mutableListOf<ByteArray>()

generateSequence(0) { it + 1 }.forEach {
    if (it % (HEAP_TO_FILL / INCREMENTS_IN_MB) == 0) list.clear()
    list.add(ByteArray(INCREMENTS_IN_MB * BYTES_TO_MB))
}

The program’s output shows how memory usage evolves under different -Xmx settings.

~ java -jar -Xmx4G app/build/libs/app.jar

INFO           Used          Free            Total
INFO       14.00 MB      36.00 MB       50.00 MB
INFO       66.00 MB      16.00 MB       82.00 MB
... (truncated) ...

With a 4 GB max heap the JVM delays GC, while a 380 MB heap triggers immediate collection. A 150 MB heap results in a java.lang.OutOfMemoryError: Java heap space after the workload exceeds the limit.

Exception in thread "main"
java.lang.OutOfMemoryError: Java heap space
    at com.dansiwiec.HeapDestroyerKt.blowHeap(HeapDestroyer.kt:28)
    ...

Metaspace usage is measured with jstat; adding Spring Boot raises metaspace from ~5 MB to ~30 MB, illustrating non‑heap growth.

~ jstat -gc 35118
MU
4731.0

Kubernetes Memory Management : Pods define requests and limits. The scheduler uses requests to place pods, while the kubelet enforces limits, restarting or evicting pods that exceed them.

JVM and Kubernetes Integration : Since Java 10, the flag -XX:+UseContainerSupport (enabled by default) lets the JVM detect container memory/CPU limits. Combined with -XX:MaxRAMPercentage, the JVM can size the max heap as a percentage of the pod’s memory limit (e.g., 75 % of a 2 GB limit → 1.5 GB heap).

Balancing heap, non‑heap, and pod limits is crucial; the sum must not exceed the pod’s limits to avoid OOMKilled events.

Scenario 1 – Java Out‑Of‑Memory : A pod with 500 Mi request/limit and -XX:MaxRAMPercentage=70 gets a 350 Mi heap. The JVM eventually throws OOM, the container exits with code 1, and Kubernetes shows CrashLoopBackOff.

INFO  Started HeapDestroyerKt in 5.599 seconds (JVM running for 6.912)
... 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space

Scenario 2 – Pod OOMKilled : Raising MaxRAMPercentage to 90 % makes the heap 450 Mi, exceeding the 500 Mi limit when non‑heap memory is added, leading kubelet to kill the pod ( OOMKilled, exit code 137).

Scenario 3 – Pod Eviction : With request: 500Mi and limit: 2500Mi, the pod fills 2.5 GB heap; when the node’s memory runs low, the pod is evicted (status Evicted) and the node logs a SystemOOM event.

Scenario 4 – Properly Tuned Pod : Setting both request and limit to 500 Mi and -XX:MaxRAMPercentage=80 keeps the JVM just under the limit; metrics show ~499 Mi RSS and healthy node resource usage.

# Inside the container
cat /sys/fs/cgroup/memory.current
523747328

Conclusion & Recommendations : Align request and limit values, increase limits only after observing Java OutOfMemory, set identical initial and maximum heap sizes for fast failure, and monitor native memory tracking for deeper insight.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMMemory ManagementKubernetes
System Architect Go
Written by

System Architect Go

Programming, architecture, application development, message queues, middleware, databases, containerization, big data, image processing, machine learning, AI, personal growth.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.