Understanding Java Heap in JDK17 — and Why You Get OOM Even When Heap Isn’t Full
👉 “Why does my JVM throw OutOfMemoryError when the heap isn’t even full?”
Understanding Java Heap in JDK17 — and Why You Get OOM Even When Heap Isn’t Full
👉 “Why does my JVM throw OutOfMemoryError when the heap isn’t even full?”
👉 “How does Java heap actually work in JDK17?”
👉 “What should I fine-tune for better performance?”
Most people still imagine the old Eden / Survivor / Old blocks.
But from Java 8 onwards (including JDK 17), the JVM uses G1GC — a region-based heap, not fixed blocks.
How Heap Actually Looks in JDK 17
JDK17 divides the heap into hundreds of tiny regions (1–32MB):
- Eden Regions → where new objects are created
- Survivor Regions → objects that survive first GC cycles
- Old Regions → long-lived objects
- Humongous Regions → very large objects
- CDS/Archive → class metadata (not part of normal GC)
G1 automatically adjusts the number of regions based on your app’s behaviour.
Why You Still Get OOM Even When the Heap Shows Free Space
This is the part most developers never learn:
1️⃣ Memory Fragmentation
Heap may have free space, but not enough contiguous space to store a large object.
So JVM fails with:
❌ “java.lang.OutOfMemoryError: Java heap space”
2️⃣ Humongous Object Allocation
If an object is too big (> 50% of region size), G1 allocates it as “humongous”.
If G1 cannot find continuous regions → OOM.
3️⃣ Promotion Failure
During GC, objects move: Eden → Survivor → Old.
If Old Gen doesn’t have space to “accept” a promoted object → JVM crashes.
4️⃣ Native Memory Exhaustion
Heap may be free, but:
- Metaspace
- DirectByteBuffer
- Thread stacks
- NIO buffers
…may be full.
This still gives you OOM even with 40–50% heap free.
Practical Tuning Tips for JDK 17
These make immediate impact:
1. Fix heap size
-Xms4g -Xmx4g
Avoid resizing at runtime.
2. Increase region size if large objects exist
-XX:G1HeapRegionSize=8m
3. Reduce OOM during GC promotions
-XX:MaxTenuringThreshold=8
-XX:SurvivorRatio=6
4. Tune pause time target (very important)
-XX:MaxGCPauseMillis=200
Higher value → fewer GCs → better throughput
5. Monitor humongous allocations
Use:
-Xlog:gc*,gc+heap=debug
Example:
Think of the JVM heap like a parking lot made of many small slots.
- Each object is a car.
- Small cars park anywhere easily.
- Large buses (humongous objects) need many empty slots together.
- Even if 40% of the parking lot is empty, those empty slots may be scattered.
So the bus still can’t park → JVM throws OOM.
This is exactly how Java OOM happens even when the heap isn’t full.
메타데이터
- post_id
- ea57c81eb23f
- slug
- understanding-java-heap-in-jdk17-and-why-you-get-oom-even-when-heap-isnt-full-ea57c81eb23f
- url
- https://medium.com/@manibandla08/understanding-java-heap-in-jdk17-and-why-you-get-oom-even-when-heap-isnt-full-ea57c81eb23f
- canonical_url
- https://medium.com/@manibandla08/understanding-java-heap-in-jdk17-and-why-you-get-oom-even-when-heap-isnt-full-ea57c81eb23f
- author_url
- https://medium.com/@manibandla08
- status
- ok
- fetched_at
- 2026-07-14 21:42:00