← Back to list

The Complete Java Interview Guide — 220+ Questions From Mid-Level to Staff Engineer Series Part 9

How to Use This Guide

Basuki Nath · 2026-06-23 16:38 · 0 claps · 13.1 min read
#java #interview #generics #multithreading
Open on Medium ↗
Wiki topics: 📚 · Books & Reading

The Complete Java Interview Guide — 220+ Questions From Mid-Level to Staff Engineer Series Part 9

How to Use This Guide

  • 🟢 Mid-Level (2–4 YOE) — You should know these cold
  • 🟡 Senior (5+ YOE) — Expected at senior interviews
  • 🔴 Staff (8+ YOE) — Deep internals, trade-offs, “explain the why”

Jump to your section:

[Hyperlink will be added in few days for better readability and access]

  1. Core Java Fundamentals
  2. OOP & Design Principles
  3. Generics & Type System
  4. Collections Framework
  5. Streams & Functional Programming
  6. Exception Handling
  7. Concurrency & Multithreading
  8. Modern Java (8 → 21)
  9. Memory Management & GC
  10. JVM Internals

Memory Management & GC

Q184: JVM heap layout 🟡

┌─────────────────────────────────────────────────────┐
│                      HEAP                           │
│  ┌─────────────────────┐  ┌──────────────────────┐ │
│  │     Young Gen        │  │      Old Gen         │ │
│  │ ┌──────┐ ┌───┐┌───┐ │  │                      │ │
│  │ │ Eden │ │S0 ││S1 │ │  │ Promoted objects     │ │
│  │ │      │ │   ││   │ │  │ (survived many GCs)  │ │
│  │ └──────┘ └───┘└───┘ │  │                      │ │
│  └─────────────────────┘  └──────────────────────┘ │
└─────────────────────────────────────────────────────┘
┌──────────────┐  ┌──────────────┐  ┌────────────────┐
│  Metaspace   │  │ Thread Stacks│  │ Direct Memory  │
│ (native mem) │  │ (per thread) │  │ (NIO buffers)  │
└──────────────┘  └──────────────┘  └────────────────┘
  • Eden: ALL new objects are born here (via TLAB — Thread-Local Allocation Buffer)
  • Survivor S0/S1: objects surviving a minor GC move here (alternate between S0 and S1)
  • Old Gen: objects surviving many minor GCs get promoted here
  • Metaspace: class metadata (replaced PermGen in Java 8), native memory, grows dynamically
  • Thread Stacks: each thread gets ~1MB (platform) or ~KB (virtual), stores frames + locals
  • Direct Memory: off-heap buffers via ByteBuffer.allocateDirect(), used by NIO
// Check memory at runtime:
Runtime rt = Runtime.getRuntime();
long heapMax = rt.maxMemory();       // -Xmx
long heapUsed = rt.totalMemory() - rt.freeMemory();

// Detailed via MXBeans:
ManagementFactory.getMemoryMXBean().getHeapMemoryUsage();
ManagementFactory.getMemoryMXBean().getNonHeapMemoryUsage();

Q185: Minor vs Major vs Full GC 🟡

Minor GC (Young Gen):

  • Triggers when Eden is full
  • Copies live objects from Eden → Survivor (S0 or S1)
  • Objects that survived enough cycles → promoted to Old Gen
  • Fast: 5–50ms typically (only scans young, which is mostly garbage)
  • After: Eden is empty, one Survivor has live objects

Major GC (Old Gen):

  • Triggers when Old Gen is filling up
  • Slower: 100ms-seconds (Old Gen is larger, more live objects)
  • G1 does “mixed” collections (young + selected old regions)

Full GC (entire heap):

  • Stop-the-world: ALL application threads paused
  • Compacts entire heap (eliminates fragmentation)
  • Triggers: Old Gen exhausted, System.gc(), Metaspace expansion
  • Should be RARE in a healthy app — if frequent, you have a leak or undersized heap
# Monitor GC:
-Xlog:gc*:file=gc.log:time,uptime,level,tags

# Key log patterns:
# "Pause Young" = Minor GC
# "Pause Full" = Full GC (BAD if frequent)
# "Concurrent Cycle" = G1/ZGC concurrent work (GOOD - no pause)

Q186: G1 vs ZGC vs Shenandoah — detailed comparison 🟡

G1 (Garbage-First) — default since Java 9:

  • Divides heap into equal-sized regions (not fixed young/old boundary)
  • Collects regions with most garbage first (hence “Garbage-First”)
  • Concurrent marking, but compaction requires stop-the-world
  • Target pause: ~200ms (tunable via -XX:MaxGCPauseMillis=200)

ZGC — production since Java 15:

  • Sub-millisecond pauses regardless of heap size (tested up to 16TB)
  • Concurrent compaction (moves objects while app runs)
  • Uses colored pointers (GC metadata stored in unused pointer bits)
  • Load barriers on every reference load (checks if pointer is stale)
  • Java 21: Generational ZGC (-XX:+ZGenerational) adds generational collection

Shenandoah — RedHat, similar goals to ZGC:

  • Sub-10ms pauses
  • Brooks pointers (forwarding pointer per object) instead of colored pointers
  • Available in OpenJDK, not in Oracle JDK
# Production flags:
-XX:+UseZGC -XX:+ZGenerational     # Best for latency (Java 21+)
-XX:+UseG1GC -XX:MaxGCPauseMillis=100  # Balanced
-XX:+UseParallelGC                  # Max throughput (batch jobs)

Follow-up: How do you choose? If P99 latency matters (APIs, event processing) → ZGC. If throughput matters more (nightly batch jobs) → Parallel. If unsure → G1 (safe default).

Q187: Container-aware JVM flags 🟡

# MUST-HAVE for containers:
-XX:MaxRAMPercentage=75.0          # Heap = 75% of container memory
-XX:+ExitOnOutOfMemoryError         # Die cleanly → K8s restarts
-XX:+UseContainerSupport            # On by default since Java 10

# WHY not -Xmx?
# Container limit may change (scaling, different environments)
# MaxRAMPercentage auto-adjusts. -Xmx3g is fixed.
# WHY 75% not 90%?
# Remaining 25% needed for:
# - Metaspace: ~150-300MB for Spring Boot apps
# - Thread stacks: 1MB × thread count (200 threads = 200MB)
# - Direct memory: NIO buffers
# - Native GC data structures
# - Code cache (JIT compiled code): 48-240MB
# Example: 4GB container
# Heap: 3GB (75%)
# Metaspace: ~250MB
# Stacks: ~200MB (200 threads)
# Direct: ~100MB
# Code cache: ~100MB
# OS/overhead: ~150MB

Q188: How ZGC achieves sub-millisecond pauses 🔴

Traditional GC pauses for: root scanning + marking + compaction.

ZGC makes marking AND compaction concurrent:

1. PAUSE (< 1ms): Scan GC roots (thread stacks, static fields)
   - Only scans roots, not entire heap
   - Fixed cost regardless of heap size

2. CONCURRENT MARK: Traverse object graph while app runs
   - Uses colored pointers to track mark state IN the pointer itself
   - No separate mark bitmap needed
3. CONCURRENT RELOCATE: Move objects while app runs
   - Copies objects to new locations
   - Uses load barriers: every reference load checks if pointer is stale
   - If stale → self-heal: update pointer to new location on-the-fly
4. PAUSE (< 1ms): Final sync - flip reference mapping
// What a load barrier looks like conceptually:
Object loadReference(Object* ref) {
    Object obj = *ref;
    if (isRelocated(obj)) {         // Check colored pointer bits
        obj = forwardingAddress(obj); // Get new location
        *ref = obj;                   // Self-heal: update in-place
    }
    return obj;
}
// This runs on EVERY object reference load — ~4% throughput cost

Q189: Memory leaks — detection and common patterns 🟡

Common leak patterns:

// 1. ThreadLocal in thread pool (most common in Spring apps)
private static final ThreadLocal<List<Event>> buffer = new ThreadLocal<>();
void process() {
    buffer.set(new ArrayList<>());
    try { doWork(); }
    finally { buffer.remove(); } // MUST remove! Thread is reused.
}

// 2. Unbounded cache
private final Map<String, byte[]> cache = new ConcurrentHashMap<>();
void store(String key, byte[] data) {
    cache.put(key, data); // Never evicts! Grows until OOM.
}
// Fix: use Caffeine with size/time limits
Cache<String, byte[]> cache = Caffeine.newBuilder()
    .maximumSize(10_000)
    .expireAfterWrite(Duration.ofMinutes(30))
    .build();
// 3. Event listener never removed
class Subscriber {
    Subscriber(EventBus bus) {
        bus.register(this); // Strong reference held by bus forever
    }
    // No unregister on disposal → this object never GC'd
}
// 4. Static collection growing forever
class AuditLog {
    static final List<String> entries = new ArrayList<>(); // Never cleaned!
}
// 5. Closeable not closed
void readData() {
    InputStream is = new FileInputStream("data.bin"); // Leak if exception before close
    // Fix: try-with-resources
}

Detection tools:

# Live monitoring:
jmap -histo:live <pid>              # Class histogram (top memory consumers)
jcmd <pid> GC.heap_info             # Heap summary

# Heap dump analysis:
jmap -dump:live,format=b,file=heap.hprof <pid>
# Open in Eclipse MAT:
# → "Leak Suspects" report (auto-detects top retainers)
# → "Dominator Tree" (what's holding the most memory)
# → "Path to GC Roots" (WHY something isn't collected)
# Auto-dump on OOM:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/

Q190: Escape analysis and scalar replacement 🔴

Escape analysis: JVM determines if an object “escapes” its creating method/thread.

Three escape levels:

  • No escape: used only within the method → can be optimized away
  • Arg escape: passed to another method but doesn’t outlive the call
  • Global escape: stored in field, returned, or shared across threads → must be heap-allocated

Scalar replacement: if object doesn’t escape, JVM decomposes it into primitive fields on the stack:

// This allocation MAY be eliminated entirely:
public double distanceFromOrigin(double x, double y) {
    Point p = new Point(x, y); // No escape — only used locally
    return Math.sqrt(p.x * p.x + p.y * p.y);
}
// After optimization: equivalent to just using x and y directly on stack
// No heap allocation, no GC pressure

// This CANNOT be optimized (escapes via return):
public Point createPoint(double x, double y) {
    return new Point(x, y); // Escapes → must be heap-allocated
}
// This CANNOT be optimized (escapes via field store):
public void register(Point p) {
    this.points.add(p); // Escapes to field → heap
}

Impact on benchmarking:

@Benchmark
public void bad() {
    Point p = new Point(1, 2); // JVM eliminates this entirely!
    double d = p.x + p.y;     // Dead code — result unused
}

@Benchmark
public double good(Blackhole bh) {
    Point p = new Point(1, 2);
    return p.x + p.y; // Returning prevents elimination
}

Q191: Weak, Soft, and Phantom references — detailed 🟡

// ═══ SOFT REFERENCE: collected only under memory pressure ═══
// Use for: memory-sensitive caches
SoftReference<LargeReport> ref = new SoftReference<>(generateReport());

LargeReport report = ref.get(); // null if GC collected it
if (report == null) {
    report = generateReport(); // Regenerate
    ref = new SoftReference<>(report);
}
// JVM keeps soft refs as long as memory allows. Under pressure → collected.
// ═══ WEAK REFERENCE: collected at next GC regardless of memory ═══
// Use for: metadata caches, canonicalization maps
WeakReference<Employee> ref = new WeakReference<>(employee);
// If no strong ref to employee exists → collected at next GC
// WeakHashMap: entries auto-removed when keys are weakly reachable
Map<Object, Metadata> cache = new WeakHashMap<>();
Object key = new Object();
cache.put(key, new Metadata());
key = null; // No strong ref to key
System.gc();
cache.size(); // 0 - entry removed
// ═══ PHANTOM REFERENCE: for cleanup (replacing finalize) ═══
// get() ALWAYS returns null. Used with ReferenceQueue.
ReferenceQueue<HeavyResource> queue = new ReferenceQueue<>();
PhantomReference<HeavyResource> phantom =
    new PhantomReference<>(resource, queue);
// Cleanup thread:
Reference<?> ref = queue.poll(); // Non-null after resource is GC'd
if (ref != null) { releaseNativeMemory(); }

Q192: String pool internals 🟡

// String Constant Pool: lives in heap (since Java 7, was PermGen before)
String a = "hello";               // Goes to pool
String b = "hello";               // Same reference as a (pooled)
String c = new String("hello");   // NEW object on heap — NOT in pool
String d = c.intern();            // Looks up pool, returns pooled reference

a == b;  // true (same pool ref)
a == c;  // false (c is separate object)
a == d;  // true (intern returns pool ref)
// String concatenation:
String s = "a" + "b";          // Compile-time constant → "ab" in pool
String x = variable + "b";    // Runtime → StringBuilder.append (Java 8)
                               // or invokedynamic (Java 9+)

String deduplication (G1/ZGC):

-XX:+UseStringDeduplication
# Doesn't deduplicate String objects — deduplicates backing char[]/byte[] arrays
# Two String objects with same content → share one underlying array
# Saves memory when many duplicate strings exist (XML parsing, log processing)

Q193: GC roots — complete list 🟡

Objects reachable from a GC root are ALIVE. Everything else is garbage.

GC Roots include:

  1. Local variables in all active thread stacks
  2. Active threads themselves (Thread objects)
  3. Static fields of loaded classes
  4. JNI references (native code holding Java object refs)
  5. Synchronized monitors (objects currently locked)
  6. JVM internal references (class objects, exception objects, classloaders)
// Common "leak" = object is unintentionally reachable from a root:

// Static field root:
class Cache {
    static final Map<String, Object> data = new HashMap<>(); // ROOT
    // Anything in this map is ALIVE forever
}
// Thread-stack root:
void longRunningMethod() {
    LargeObject obj = new LargeObject(); // On stack = ROOT
    processForHours(); // obj stays alive entire time even if not used after line 1
    // Fix: set obj = null before the long operation if it's no longer needed
}

Q194: TLAB and object allocation cost 🔴

// TLAB = Thread-Local Allocation Buffer
// Each thread gets a chunk of Eden pre-allocated exclusively to it
// Allocation = increment a pointer (bump pointer) — NO synchronization!

// Cost of `new Object()`:
// 1. Check if TLAB has space (pointer comparison) - 1 instruction
// 2. Bump pointer forward by object size - 1 instruction
// 3. Zero memory (optional, JVM may skip) - few instructions
// Total: ~10 CPU instructions. EXTREMELY cheap.
// Implication:
// Don't pool small objects (POJOs, records, small arrays)
// Object pooling adds: synchronization, state reset, lifecycle management
// That overhead > allocation cost for objects < 1KB
// When pooling DOES help:
// - Objects expensive to CREATE (not allocate): DB connections, SSL contexts
// - Objects expensive to INITIALIZE: large buffers requiring OS calls

Q195: OutOfMemoryError variants 🟡

// 1. Java heap space — most common
// Cause: heap full, GC can't free enough
// Fix: increase -Xmx, fix memory leak, reduce object creation rate
java.lang.OutOfMemoryError: Java heap space

// 2. Metaspace - class metadata overflow
// Cause: too many classes loaded (classloader leak, dynamic proxies)
// Fix: -XX:MaxMetaspaceSize=512m, fix classloader leak
java.lang.OutOfMemoryError: Metaspace
// 3. GC overhead limit exceeded
// Cause: >98% of time spent in GC, recovering <2% of heap
// Means: heap is nearly full of live objects (leak or undersized)
java.lang.OutOfMemoryError: GC Overhead limit exceeded
// 4. Direct buffer memory
// Cause: ByteBuffer.allocateDirect() exceeded limit
// Fix: -XX:MaxDirectMemorySize=512m, close buffers properly
java.lang.OutOfMemoryError: Direct buffer memory
// 5. Unable to create native thread
// Cause: OS thread limit (ulimit -u) or no memory for stack
// Fix: increase ulimit, reduce thread count, use virtual threads
java.lang.OutOfMemoryError: unable to create native thread

Q196: Metaspace deep dive 🟡

// What lives in Metaspace:
// - Class metadata (field info, method info, constant pool)
// - Method bytecodes
// - Annotations
// - Static variables (reference pointers — actual objects on heap)

// Key properties:
// - Native memory (not limited by -Xmx)
// - Grows dynamically (no fixed size like old PermGen)
// - Freed when ClassLoader is GC'd (all classes loaded by it become unreachable)
// Common Metaspace leak:
// App server hot-reload: each redeploy creates new ClassLoader
// Old ClassLoader not GC'd because something holds a reference
// Classes accumulate → Metaspace grows → OOM
# Monitor:
jcmd <pid> VM.metaspace   # Detailed metaspace stats

# Limits:
-XX:MetaspaceSize=256m      # When to trigger first GC for metaspace
-XX:MaxMetaspaceSize=512m   # Hard ceiling (default: unlimited - dangerous!)

Q197: JMH — proper benchmarking 🔴

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS)
@Fork(2) // Separate JVM instances — avoids profile pollution
@State(Scope.Thread) // Each thread gets own state
public class PayrollBenchmark {

private Employee employee;
    @Setup
    public void setup() {
        employee = createRealEmployee(); // Use realistic data
    }
    @Benchmark
    public BigDecimal measureTaxCalc() {
        return calculateTax(employee); // RETURN result - prevents dead code elimination
    }
    @Benchmark
    public void measureWithBlackhole(Blackhole bh) {
        bh.consume(calculateTax(employee)); // Alternative: consume to prevent DCE
    }
}

Common pitfalls:

// PITFALL 1: Dead code elimination
@Benchmark
public void bad() { calculateTax(emp); } // Result unused → JVM may eliminate entirely

// PITFALL 2: Constant folding
@Benchmark
public int bad2() { return 2 * 3; } // Compiler folds to 6 → measures nothing
// PITFALL 3: Loop optimization
@Benchmark
public void bad3() {
    for (int i = 0; i < 1000; i++) calc(emp); // JVM may hoist out of loop
}
// PITFALL 4: Not forking (profile pollution from previous benchmarks)
// ALWAYS @Fork(2) minimum
// PITFALL 5: Insufficient warmup (JIT hasn't compiled hot paths yet)
// Default 5 iterations is usually enough, but verify with -prof perfasm

Q198: Direct memory (off-heap) 🔴

// Heap buffer: backed by byte[], managed by GC
ByteBuffer heap = ByteBuffer.allocate(1024);
// GC handles lifecycle. Safe but slower for I/O (extra copy to kernel buffer).

// Direct buffer: off-heap, OS-managed memory
ByteBuffer direct = ByteBuffer.allocateDirect(1024);
// NO GC overhead. Faster I/O (zero-copy to kernel possible).
// But: expensive to allocate (~100x slower than heap buffer), must manage lifecycle.
// When to use direct:
// - Long-lived buffers reused across many I/O operations
// - Large buffers for NIO channels (network, file I/O)
// - When you need memory-mapped files (FileChannel.map)
// When NOT to use:
// - Short-lived, small buffers (allocation cost dominates)
// - You don't control the lifecycle (risk of leak)
// Monitoring:
-XX:MaxDirectMemorySize=256m  // Limit. Default = -Xmx value.
// Leak risk:
// DirectByteBuffer is GC'd like any object. But the native memory
// is freed by a Cleaner WHEN the Java object is GC'd.
// If you allocate many direct buffers without triggering GC → OOM: Direct buffer memory
// Fix: explicitly clean or trigger System.gc() (or just use heap buffers for short-lived work)

Q199: GC tuning — key metrics and flags 🟡

# Enable detailed GC logging (Java 11+):
-Xlog:gc*:file=gc.log:time,uptime,level,tags:filecount=5,filesize=10m

# Key metrics to monitor (via Prometheus/Grafana):

What to watch:

  1. GC pause time (P99) — must be < your latency SLA
  2. GC throughput — % of time NOT in GC. Target: >95% (>98% ideal)
  3. Heap occupancy after GC — if Old Gen stays high after Full GC → LEAK
  4. Promotion rate — bytes/sec from Young → Old. High = too many medium-lived objects
  5. Allocation rate — bytes/sec into Eden. Very high = too many objects created
# Common tuning:
-XX:MaxGCPauseMillis=100      # G1: target pause time (trades throughput)
-XX:InitiatingHeapOccupancyPercent=45  # G1: start concurrent marking earlier
-XX:G1HeapRegionSize=16m      # Larger regions for large heaps
-XX:+AlwaysPreTouch           # Pre-fault pages at startup (avoids latency spikes later)

Q200: G1 garbage collection process — detailed 🔴

Phase 1: Young-Only Collections
  - Only collects Eden + Survivor regions
  - Promotes survivors to Old regions
  - Triggered when Eden is full
  - Pause: ~10-50ms
Phase 2: Concurrent Marking (starts when IHOP threshold hit)
  - IHOP = Initiating Heap Occupancy Percent (default ~45%)
  - Scans entire heap concurrently (snapshot-at-the-beginning)
  - Identifies which Old regions have the most garbage
  - Runs while app continues (minimal pause for root scan)
Phase 3: Mixed Collections
  - Collects Young regions + selected Old regions (most garbage first)
  - "Garbage-First" = collect regions with highest garbage ratio
  - Multiple mixed GCs until Old Gen is sufficiently cleared
  - Pause: ~50-200ms (tunable)
Phase 4: Full GC (FALLBACK - should be rare)
  - Triggers if mixed GCs can't keep up with promotion rate
  - Stop-the-world, compacts entire heap
  - Indicates: heap too small, leak, or IHOP set too late

# G1 heap structure:
# [E][E][E][S][O][O][H][O][E][S][O][O]...
# E=Eden, S=Survivor, O=Old, H=Humongous (objects > region/2)
# Regions are 1-32MB each (auto-sized, or -XX:G1HeapRegionSize)

Q201: Heap dump analysis — step by step 🟡

# Step 1: Get the dump
# Option A: On OOM (automatic)
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dumps/

# Option B: Manual (live system)
jmap -dump:live,format=b,file=heap.hprof <pid>
# Option C: Via jcmd (preferred - safer)
jcmd <pid> GC.heap_dump /tmp/heap.hprof

Step 2: Open in Eclipse MAT

Key views:

  1. Leak Suspects Report — MAT auto-analyzes and suggests top leak candidates
  2. Dominator Tree — “what single object retains the most memory?” Shows retained heap per object.
  3. Histogram — class-level: “there are 5 million String objects consuming 400MB”
  4. Path to GC Roots — “WHY isn’t this collected?” Shows the reference chain from GC root to the leaking object.
  5. OQL (Object Query Language) — SQL-like queries: SELECT * FROM java.lang.String WHERE toString().length() > 10000

Step 3: Common patterns you’ll find:

  • Large char[] arrays → String leak (check who holds the Strings)
  • Many HashMap$Node → unbounded map
  • Thread objects with large locals → ThreadLocal leak
  • Multiple ClassLoader instances → hot-reload leak

Q202: Cleaner API — replacing finalize() 🔴

// finalize() problems:
// 1. Unpredictable timing — may never run
// 2. Resurrection possible — object can become reachable again in finalize()
// 3. GC overhead — finalized objects survive extra GC cycle
// 4. Single finalizer thread — one slow finalizer blocks all others
// 5. Deprecated for removal in Java 18+

// Cleaner API (Java 9+):
public class NativeResource implements AutoCloseable {
    private static final Cleaner cleaner = Cleaner.create();
    // Cleaning action - MUST NOT reference the enclosing object!
    // (otherwise it prevents GC of the object we're trying to clean)
    private static class CleaningAction implements Runnable {
        private long nativePointer;
        CleaningAction(long ptr) { this.nativePointer = ptr; }
        public void run() { freeNative(nativePointer); }
    }
    private final Cleaner.Cleanable cleanable;
    NativeResource() {
        long ptr = allocateNative();
        cleanable = cleaner.register(this, new CleaningAction(ptr));
    }
    @Override
    public void close() {
        cleanable.clean(); // Deterministic cleanup (preferred path)
    }
    // If close() never called → Cleaner runs action when GC collects this object
    // Safety net, not primary mechanism
}

Q203: ExitOnOutOfMemoryError in production 🟡

# Without either flag: JVM continues in broken state after OOM
# - Some threads dead, some alive
# - Half-processed data, inconsistent state
# - Monitoring shows "alive" but it's a zombie
# - Manual intervention needed

# With -XX:+ExitOnOutOfMemoryError:
# - JVM calls System.exit(1) immediately on OOM
# - Process exits cleanly
# - Kubernetes detects exit → restarts pod automatically
# - Fast recovery (seconds), no zombie state
# With -XX:+CrashOnOutOfMemoryError:
# - JVM generates core dump (hs_err_pid.log) then crashes
# - More info for debugging, but messier exit
# - Use if you need the crash dump for analysis
# ALWAYS use one of these in containers:
-XX:+ExitOnOutOfMemoryError  # Recommended for K8s/ECS
-XX:+HeapDumpOnOutOfMemoryError  # Also add this - dump before exit

메타데이터
post_id
b5985e2aaac6
slug
the-complete-java-interview-guide-220-questions-from-mid-level-to-staff-engineer-series-part-9-b5985e2aaac6
url
https://medium.com/@basukinath/the-complete-java-interview-guide-220-questions-from-mid-level-to-staff-engineer-series-part-9-b5985e2aaac6
canonical_url
https://medium.com/@basukinath/the-complete-java-interview-guide-220-questions-from-mid-level-to-staff-engineer-series-part-9-b5985e2aaac6
author_url
https://medium.com/@basukinath
status
ok
fetched_at
2026-07-13 06:23:13