Java Memory Management
& Garbage Collection
Complete Interview Question Bank
60+ Questions • All Difficulty Levels • Model Answers
Basic · Intermediate · Advanced · Expert
■ Table of Contents
1. Java Memory Model Fundamentals
2. Heap & Stack Deep Dive
3. Garbage Collection Algorithms
4. GC Tuning & JVM Flags
5. Memory Leaks & Troubleshooting
6. Reference Types
7. Out-Of-Memory Errors
8. Concurrency & Memory Visibility
9. Advanced / Expert Level
10. Scenario & Coding Questions
■ 1. Java Memory Model Fundamentals
Q1. Basic
What is the Java Memory Model (JMM) and why is it important?
Answer:
The JMM defines how threads interact through memory. It specifies the rules for visibility, atomicity, and
ordering of shared variable access across threads.
It guarantees that under synchronized access, changes made by one thread become visible to others in
a well-defined manner.
Without JMM guarantees, compilers and CPUs can reorder instructions, leading to unexpected behavior
in concurrent programs.
■ Tip: JMM is defined in JSR 133 (Java 5+) and is the foundation of [Link].
Q2. Basic
List and describe all memory areas in the JVM.
Answer:
Heap: Stores all object instances and arrays. Shared among all threads. GC-managed.
Stack (JVM Stack): Per-thread; holds stack frames (local variables, operand stack, frame data).
Method Area / Metaspace (Java 8+): Stores class metadata, static fields, constant pool.
Program Counter (PC) Register: Per-thread; holds address of the current instruction.
Native Method Stack: Supports native (JNI) method execution.
Code Cache: Stores JIT-compiled native code.
Q3. Basic
What is the difference between the Heap and the Stack in Java?
Answer:
Heap: Dynamic, shared, GC-collected, stores objects and arrays, larger in size.
Stack: Per-thread, LIFO, auto-freed on method return, stores primitives and references (not the objects
themselves), much smaller.
A StackOverflowError means the stack is full (deep recursion). An OutOfMemoryError (heap space)
means the heap is full.
Intermediat
Q4. e
What changed between PermGen (Java 7) and Metaspace (Java 8+)?
Answer:
PermGen was a fixed-size region in the heap storing class metadata. It caused
[Link]: PermGen space in apps that loaded many classes (e.g., app servers).
Metaspace replaces PermGen and lives in native memory (off-heap), growing automatically by default.
Key flags: -XX:MaxMetaspaceSize=256m limits growth; -XX:MetaspaceSize= sets initial size.
Class metadata is still GC-collected when classloaders are GC'd.
■ Tip: Metaspace can still OOM if class generation is unbounded (e.g., reflection proxies, CGLIB).
Q5. Advanced
What are the happens-before guarantees in the JMM?
Answer:
A happens-before relationship ensures that memory writes by one action are visible to another action.
Key rules: (1) Program order: each action HB the next in the same thread. (2) Monitor lock: unlock HB
subsequent lock. (3) volatile write HB subsequent read. (4) Thread start: [Link]() HB any action in
the started thread. (5) Thread join: all actions in a thread HB a successful [Link]() return.
■■ 2. Heap & Stack Deep Dive
Intermediat
Q6. e
Describe the generational heap structure in HotSpot JVM.
Answer:
Young Generation: New objects are allocated here. Consists of Eden and two Survivor spaces (S0, S1).
Minor GC is triggered when Eden fills.
Old Generation (Tenured): Objects that survive several Minor GCs are promoted here. Major/Full GC
collects it.
Metaspace: Class metadata, not part of heap.
Allocation is fast via Thread-Local Allocation Buffers (TLABs) — each thread gets a private chunk of
Eden.
Q7. Advanced
What is a TLAB and why does it matter for performance?
Answer:
Thread-Local Allocation Buffer (TLAB) is a per-thread region inside Eden. Object allocation simply
bumps a pointer — no synchronization needed.
This makes object creation extremely fast (O(1)).
When a TLAB is exhausted, the thread requests a new one; if Eden is full, a Minor GC is triggered.
Controlled with -XX:+UseTLAB (on by default) and -XX:TLABSize.
Intermediat
Q8. e
What is object promotion and what triggers it?
Answer:
Objects that survive Minor GC are copied between S0 and S1 survivor spaces. Each survival
increments the object's age counter.
When age reaches the tenuring threshold (default 15), the object is promoted to Old Gen.
Premature promotion happens when survivors are too full (-XX:TargetSurvivorRatio), causing objects to
be promoted earlier.
Flags: -XX:MaxTenuringThreshold, -XX:+PrintTenuringDistribution.
Q9. Advanced
What is Humongous allocation in G1GC?
Answer:
Objects larger than 50% of a G1 region size are considered Humongous and are allocated directly in the
Old Generation (contiguous humongous regions).
They bypass Eden and are collected only during concurrent or Full GC cycles, which can cause GC
pauses.
Tuning: increase -XX:G1HeapRegionSize (1–32 MB, power of 2) to make more objects
non-humongous.
■■ 3. Garbage Collection Algorithms
Intermediat
Q10. e
What are the main GC collectors available in modern JVMs?
Answer:
Serial GC (-XX:+UseSerialGC): Single-threaded, stop-the-world. For small apps or constrained
environments.
Parallel GC (-XX:+UseParallelGC): Multi-threaded throughput collector. Default in Java 8 for many
configs.
CMS (-XX:+UseConcMarkSweepGC): Concurrent Mark Sweep; low-pause but fragmentation-prone.
Removed in Java 14.
G1GC (-XX:+UseG1GC): Default in Java 9+. Region-based, predictable pauses, good throughput
balance.
ZGC (-XX:+UseZGC): Ultra-low latency (<1ms pauses), available since Java 11, production-ready in
Java 15.
Shenandoah (-XX:+UseShenandoahGC): Concurrent compaction, Red Hat; available in OpenJDK.
Q11. Basic
Explain the Mark-Sweep-Compact algorithm.
Answer:
Mark phase: GC traverses the object graph from GC roots, marking all reachable (live) objects.
Sweep phase: Scans heap and reclaims memory occupied by unmarked (dead) objects.
Compact phase: Moves live objects together to eliminate fragmentation and reset the allocation pointer.
Stop-the-world pauses occur during all three phases in basic implementations. Concurrent collectors
overlap some phases with application threads.
Intermediat
Q12. e
How does G1GC work? What makes it different from older collectors?
Answer:
G1 divides the heap into equal-sized regions (1–32 MB). Regions are dynamically assigned as Eden,
Survivor, Old, or Humongous.
Young-only phase: concurrent marking identifies live data. Mixed GC phase: collects young + selected
old regions with most garbage.
G1 aims to meet a pause-time target (-XX:MaxGCPauseMillis=200). It prioritizes regions with the most
garbage (Garbage First).
Concurrent marking runs alongside the application, reducing STW pauses compared to Parallel GC.
Q13. Advanced
How does ZGC achieve sub-millisecond pauses?
Answer:
ZGC uses colored pointers (load barriers) to track object state within the pointer itself (not the object
header).
Almost all GC work (marking, relocation, remapping) runs concurrently with the application.
STW pauses are only for root scanning and are typically < 1ms regardless of heap size.
ZGC supports multi-terabyte heaps and is scalable across heap sizes.
■ Tip: In Java 21, ZGC became generational (ZGC with generations) for even better throughput.
Q14. Advanced
What is a 'stop-the-world' pause? Why can't we eliminate it entirely?
Answer:
A STW pause suspends all application threads to allow the GC to perform work safely (e.g., consistent
snapshot of the heap).
It is needed because moving objects requires updating all references, which is unsafe while threads are
running.
Modern collectors minimize STW via concurrent phases but can't fully eliminate them: initial mark,
remark, and final reference processing usually need brief STW pauses.
ZGC and Shenandoah get very close to eliminating them by using load barriers and
incremental/concurrent relocation.
Intermediat
Q15. e
What is Concurrent Mark Sweep (CMS) and why was it deprecated?
Answer:
CMS performs concurrent marking and sweeping to avoid long STW pauses. It was popular for
latency-sensitive apps.
Problems: (1) No compaction → heap fragmentation → eventual concurrent mode failure → Full GC. (2)
CPU-intensive concurrent phases steal app CPU. (3) Promotion failures if Old Gen fills faster than CMS
can collect.
Deprecated in Java 9, removed in Java 14. G1GC and ZGC are preferred replacements.
■■ 4. GC Tuning & JVM Flags
Q16. Basic
What JVM flags do you use to set heap size?
Answer:
-Xms: Initial heap size (e.g., -Xms512m).
-Xmx: Maximum heap size (e.g., -Xmx4g).
Best practice: Set -Xms == -Xmx in production to avoid resizing pauses.
-XX:NewRatio=n: Ratio of Old to Young Gen (default 2, meaning Young = 1/3 of heap).
-XX:NewSize / -XX:MaxNewSize: Explicit Young Gen sizing.
-Xms2g -Xmx2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
Intermediat
Q17. e
What GC logging flags should you use in Java 11+?
Answer:
Java 9+ unified logging: -Xlog:gc* for verbose GC logs.
Common: -Xlog:gc:file=/var/log/[Link]:time,uptime,level,tags:filecount=5,filesize=20m
Java 8 equivalent: -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/var/log/[Link]
Tools: GCEasy, GCViewer, JDK Mission Control can parse and visualize logs.
-Xlog:gc*:file=/tmp/[Link]:time,uptime:filecount=3,filesize=10m
Q18. Advanced
How do you tune G1GC for low latency?
Answer:
Set a pause target: -XX:MaxGCPauseMillis=100 (default 200ms).
Avoid Humongous allocations: increase -XX:G1HeapRegionSize.
Tune Mixed GC: -XX:G1MixedGCCountTarget, -XX:G1HeapWastePercent.
Increase concurrent threads: -XX:ConcGCThreads.
Monitor with GC logs and adjust. Don't set -Xmn with G1 (G1 manages Young Gen dynamically).
Intermediat
Q19. e
What is GC overhead limit exceeded and how do you fix it?
Answer:
JVM throws [Link]: GC overhead limit exceeded when >98% of time is spent in
GC recovering <2% of heap.
Root causes: heap too small, memory leak, too many large objects.
Fixes: increase -Xmx, find and fix memory leaks (heap dump analysis), optimize object creation
patterns.
Disable (not recommended): -XX:-UseGCOverheadLimit.
Q20. Advanced
What is Ergonomics in JVM GC?
Answer:
JVM Ergonomics automatically selects the GC, heap size, and runtime compiler based on the platform.
On a server-class machine (multi-core, >=1GB RAM), JVM selects server VM + Parallel or G1 GC.
Adaptive Sizing (-XX:+UseAdaptiveSizePolicy, on by default) dynamically adjusts Eden, Survivor, and
Old Gen sizes based on GC performance goals.
Goals: minimize footprint, maximize throughput, meet pause target (in that priority).
■ 5. Memory Leaks & Troubleshooting
Intermediat
Q21. e
What causes memory leaks in Java and how do you detect them?
Answer:
Common causes: Static collections holding references, unclosed resources (streams, connections),
listeners not deregistered, inner class references to outer class, caches without eviction.
Detection: Monitor heap growth over time via JConsole/VisualVM. Capture heap dumps
(-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/). Analyze with Eclipse MAT or
JProfiler.
Look for: objects with unexpectedly high retention, dominant retained sizes, GC roots holding large
object graphs.
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/[Link]
Intermediat
Q22. e
What is a heap dump and how do you analyze it?
Answer:
A heap dump is a snapshot of all objects in the JVM heap at a point in time, saved as a .hprof file.
Generate: jmap -dump:live,format=b,file=[Link] or automatically on OOM.
Analyze with Eclipse Memory Analyzer (MAT): use 'Leak Suspects Report' to find top retained objects
and their GC root paths.
Key metrics: retained heap (memory freed if object were GC'd), shallow heap (object itself), dominator
tree.
Intermediat
Q23. e
How do you use jstat to monitor GC activity?
Answer:
jstat -gcutil 1000 prints GC statistics every second: % Eden used, % Survivor, % Old, YGC count,
YGCT, FGC count, FGCT.
jstat -gc : raw sizes in KB.
jstat -gccause : includes last and current GC cause.
Look for: rapidly rising Old Gen %, increasing FGC count, high FGCT indicating long Full GC pauses.
jstat -gcutil $(pgrep -f MyApp) 1000 20
Q24. Advanced
What is a Finalize queue issue and how do you mitigate it?
Answer:
Objects with finalizers cannot be immediately reclaimed. After GC marks them dead, they are enqueued
in the finalizer queue and processed by a single Finalizer thread.
If finalizers are slow or the queue backs up, objects accumulate in Old Gen causing OOM.
Mitigation: Avoid finalizers. Use try-with-resources / Cleaner (Java 9+) / PhantomReference instead.
Monitor: jmap -finalizerinfo shows pending finalizable objects.
Q25. Advanced
How do you diagnose a [Link]: unable to create new native
thread?
Answer:
This OOM is not a heap issue — the OS cannot allocate more threads (OS thread limit or virtual
memory exhausted).
Causes: thread leak (threads created but never terminated), too many threads for the process's address
space, OS limit (/proc/sys/kernel/threads-max).
Fix: reduce thread stack size (-Xss256k), use thread pools, check for thread leaks with jstack or thread
dump analysis.
On Linux: ulimit -u shows max user processes.
■ 6. Reference Types
Intermediat
Q26. e
Explain the four reference types in Java.
Answer:
Strong Reference: Default. Object is not GC'd as long as a strong reference exists.
Soft Reference (SoftReference): GC'd only when heap is low. Good for caches.
Weak Reference (WeakReference): GC'd at next GC cycle regardless of memory. Used in
WeakHashMap, canonicalizing mappings.
Phantom Reference (PhantomReference): Enqueued after object is finalized; get() always returns null.
Used for post-mortem cleanup (replacement for finalize).
Intermediat
Q27. e
How does WeakHashMap work and when should you use it?
Answer:
WeakHashMap holds weak references to its keys. When a key has no strong/soft references elsewhere,
it becomes eligible for GC, and the entry is automatically removed.
Use cases: metadata caches keyed on objects, listener maps, canonicalization tables.
Pitfall: if the value (not key) strongly references the key, the key won't be GC'd — creating a memory
leak.
Not thread-safe; use [Link] or ConcurrentReferenceHashMap for concurrent
use.
Q28. Advanced
What is a ReferenceQueue and how is it used?
Answer:
A ReferenceQueue is a queue to which the GC enqueues a Reference object after the referent
becomes unreachable.
Used to take action after an object is GC'd without overriding finalize(). Combine with
PhantomReference for resource cleanup.
Pattern: create PhantomReference with a ReferenceQueue; poll the queue in a cleanup thread to
release native resources.
ReferenceQueue queue = new ReferenceQueue<>(); PhantomReference ref = new
PhantomReference<>(obj, queue);
■ 7. Out-Of-Memory Error Types
OOM Message Cause Fix
Java heap space Heap is full; objects can't be allocated. Increase -Xmx or fix leaks.
GC overhead limit exceeded >98% time in GC, <2% freed. Increase heap or fix leaks.
Metaspace Class metadata area full. Add -XX:MaxMetaspaceSize or fix
class loader leaks.
unable to create native OS thread limit reached. Reduce thread count, increase OS
thread limits.
Direct buffer memory Off-heap NIO buffer pool exhausted. Increase -XX:MaxDirectMemorySize.
request size bytes for Native heap exhausted. Add swap, reduce native memory
reason. Out of swap space? usage.
Compressed class space Small area for compressed class pointers Increase
full. -XX:CompressedClassSpaceSize.
Q29. Advanced
What is Direct Memory in Java and when does it OOM?
Answer:
Direct memory (off-heap) is allocated via [Link]() and is not subject to normal GC.
Used by NIO channels, Netty, Kafka, etc. for zero-copy I/O.
Controlled by -XX:MaxDirectMemorySize (default: equal to -Xmx).
DirectByteBuffers are freed when their associated Cleaner (phantom reference) runs — which only
happens after GC. Heavy allocation without GC can OOM direct memory.
■ 8. Concurrency & Memory Visibility
Intermediat
Q30. e
What does volatile guarantee in Java?
Answer:
Visibility: A write to a volatile variable is immediately visible to all threads reading that variable.
Ordering: Writes to volatile create a happens-before relationship with subsequent reads, preventing
reordering across the volatile access.
Does NOT guarantee atomicity for compound actions (e.g., volatile int i; i++ is still a read-modify-write
race).
private volatile boolean running = true; // safe for single-writer,
multiple-reader flag patterns
Intermediat
Q31. e
How does synchronized relate to the Java Memory Model?
Answer:
Acquiring a monitor (entering synchronized block) causes the thread to read fresh values from main
memory.
Releasing a monitor (exiting synchronized) flushes all writes to main memory.
This provides both atomicity (mutual exclusion) and visibility (happens-before).
synchronized methods lock on 'this' (instance) or the class object (static method).
Q32. Expert
What is false sharing and how do you avoid it?
Answer:
False sharing occurs when two threads access different variables that happen to reside on the same
CPU cache line (typically 64 bytes). Updating one variable invalidates the other thread's cache line,
causing performance degradation.
Detection: Java Flight Recorder, async-profiler (cache misses).
Mitigation: @Contended annotation (JDK 8+, requires -XX:-RestrictContended), manual padding, or
putting hot fields in separate objects.
@[Link] private volatile long counter; // padded to
own cache line
■ 9. Advanced & Expert Level
Q33. Expert
What is Escape Analysis and how does it affect memory allocation?
Answer:
Escape Analysis (EA) is a JIT compiler optimization that determines whether an object 'escapes' its
creating method or thread.
If an object doesn't escape: (1) Stack Allocation — object is allocated on the stack, avoiding heap
pressure and GC. (2) Scalar Replacement — object fields are stored in registers/locals, and the object
is never created at all. (3) Lock Elision — synchronization on a non-escaping object can be removed.
EA is enabled by default: -XX:+DoEscapeAnalysis (on since Java 6u23).
Q34. Expert
Explain the Remembered Set and Card Table in generational GC.
Answer:
When Old Gen objects reference Young Gen objects, GC must find those references during Minor GC
without scanning the entire Old Gen.
Card Table: Old Gen is divided into 512-byte cards. A card is marked 'dirty' when a write to that card's
region occurs (via write barrier).
Remembered Set: G1 uses per-region remembered sets that track which regions reference the current
region.
During Minor GC, only dirty cards are scanned, making Young GC fast despite cross-generational
references.
Q35. Expert
What is NUMA-aware memory allocation in the JVM?
Answer:
On Non-Uniform Memory Access (NUMA) systems, memory access latency varies depending on which
CPU node allocated the memory.
JVM NUMA support: -XX:+UseNUMA causes the JVM to allocate Eden for each NUMA node, so
objects created by threads on node N are allocated in node N's memory, improving cache locality.
Works best with Parallel GC. G1 has partial NUMA support since Java 14.
Verify with -XX:+PrintNUMAInitializationInfo.
Q36. Expert
What is Shenandoah GC's Brooks pointer technique?
Answer:
Shenandoah uses an indirection pointer (Brooks pointer) added to every object. Rather than updating all
references when an object is moved, only the forwarding pointer in the old location is updated.
Concurrent relocation: while app threads run, Shenandoah evacuates objects and updates Brooks
pointers. Load barriers intercept reads and redirect to the new location.
This allows concurrent compaction without STW, at the cost of extra memory (one pointer per object)
and slight read overhead.
Intermediat
Q37. e
What is the difference between Minor GC, Major GC, and Full GC?
Answer:
Minor GC: Collects only the Young Generation. Triggered when Eden fills. Short, frequent STW pauses.
Objects surviving are promoted.
Major GC: Collects the Old Generation. Often triggered by promotion failure or occupancy threshold.
Longer pauses.
Full GC: Collects entire heap (Young + Old + Metaspace). Most expensive. Triggered by [Link](),
promotion failure, Metaspace full, CMS concurrent mode failure, etc.
Note: 'Major GC' and 'Full GC' are often used interchangeably but technically differ — Full GC also
clears Metaspace and code cache.
■ 10. Scenario & Coding Questions
Q38. Advanced
You see a '[Link]: Java heap space' in production. Walk through
your debugging steps.
Answer:
1. Check if it's a spike or a trend: plot heap usage over time (JMX metrics, Prometheus).
2. Capture heap dumps: ensure -XX:+HeapDumpOnOutOfMemoryError is set for the next occurrence.
3. Analyze the heap dump in Eclipse MAT: Leak Suspects report, dominator tree, largest retained
objects.
4. Check GC logs: is Old Gen growing steadily (leak) or spiking (burst allocation)?
5. Review recent code changes for new caches, static collections, connection pools.
6. Short-term fix: increase -Xmx. Long-term fix: address the root cause.
Intermediat
Q39. e
Find the memory leak in this code:
Answer:
The list is static and grows unboundedly — Cache entries are never evicted.
Fix: use a bounded cache (LinkedHashMap with removeEldestEntry), or Caffeine/Guava Cache with
TTL/size limits.
Also: if the cached objects hold references to large graphs, the retained memory compounds.
public class Cache { private static final List cache = new ArrayList<>(); public
void store(byte[] data) { [Link](data); // LEAK: never removed! } }
Intermediat
Q40. e
What is the output, and is there a GC concern?
Answer:
Output: 'Object created' once, then 'Finalized' at some later point (not deterministically).
GC concern: Finalization is non-deterministic and delays object reclamation by at least one GC cycle.
The object may survive several GC cycles before the Finalizer thread processes it.
Best practice: Don't rely on finalize() for resource cleanup. Use try-with-resources or Cleaner.
class Res { protected void finalize() { [Link]("Finalized"); } } //
new Res(); [Link](); — output is non-deterministic
Intermediat
Q41. e
How would you implement a memory-efficient LRU cache in Java?
Answer:
Use LinkedHashMap with accessOrder=true and override removeEldestEntry to evict the oldest entry
when size exceeds the limit.
Wrap in [Link] or use ConcurrentHashMap + a LinkedList for thread safety.
For production: use Caffeine ([Link]/ben-manes/caffeine) which provides O(1) O&M;, TTL,
weak/soft value references, and stats.
new LinkedHashMap(capacity, 0.75f, true) { protected boolean
removeEldestEntry([Link] e) { return size() > MAX_SIZE; } };
Q42. Expert
You have a latency-sensitive microservice. Which GC would you choose and how
would you tune it?
Answer:
Choose ZGC (Java 17+ for generational ZGC) or Shenandoah for sub-millisecond pause targets.
ZGC tuning: -XX:+UseZGC -Xms4g -Xmx4g -XX:+UseTransparentHugePages (Linux). ZGC is
self-tuning; set -XX:SoftMaxHeapSize to leave headroom.
Monitor: -Xlog:gc*:file=/var/log/[Link]:time and alert on pause times > threshold.
Profile allocation rate: high allocation → more frequent GC cycles → higher latency variability.
Java Memory & GC Interview Guide • 60+ Questions • All Levels • 2024