JVM internals are a staple of senior Java interviews. These questions cover memory areas, garbage collection, class loading, and performance.

Memory Areas

Q: Describe JVM memory structure.

  ┌─────────────────────────────────────────┐
│ Thread-shared:                           │
│   Heap (objects)                         │
│   Metaspace (class metadata)             │
│   Code Cache (JIT compiled code)         │
│ Thread-private:                          │
│   Program Counter Register               │
│   JVM Stack (frames, local vars)         │
│   Native Method Stack                    │
└─────────────────────────────────────────┘
  

Q: Stack vs Heap?

Stack Heap
Stores Method frames, local variables, references Objects, arrays
Size Fixed per thread (~1MB default) Configurable (-Xmx)
GC No Yes
Thread Per-thread Shared
Overflow StackOverflowError OutOfMemoryError
  void method() {
    int x = 10;           // stack (primitive)
    Person p = new Person();  // reference on stack, object on heap
}
  

Garbage Collection

Q: Which objects are eligible for GC?

Objects not reachable from GC roots:

  • Static variables
  • Active thread stacks
  • JNI references
  • Syncmonitors

Q: Describe GC roots and reachability.

  GC Root → Object A → Object B → Object C
                  ↘ Object D

If reference from A to D is removed, D becomes eligible for GC
(even if B still exists and B originally created D)
  

Q: G1 vs CMS vs ZGC?

CMS (deprecated) G1 (default) ZGC
Pause type Concurrent mark, STW compact Incremental regions Nearly all concurrent
Fragmentation Yes (no compact) Compacts regions Compacts
Heap size Medium Medium–large Large (8g+)
Pause target Unpredictable Configurable (200ms) Sub-ms
Status Removed in Java 14 Default since Java 9 Production since Java 15

Q: What triggers a Full GC?

  1. Old generation fills up
  2. Metaspace exhaustion
  3. System.gc() called (usually ignored in production)
  4. Allocation failure after minor GC
  5. Heap dump request

Class Loading

Q: Class loading process?

  Loading → Linking (verify, prepare, resolve) → Initialization
  
  1. Loading — find bytecode, create Class object
  2. Verify — bytecode validity
  3. Prepare — allocate static variable memory, set defaults
  4. Resolve — symbolic references → direct references (optional)
  5. Initialize — execute static blocks, assign static fields

Q: Parent delegation model?

  Bootstrap ClassLoader (rt.jar)
  ↑
Extension ClassLoader (ext/)
  ↑
Application ClassLoader (classpath)
  ↑
Custom ClassLoader
  

A classloader asks its parent first. Only loads if parent cannot find the class. Prevents core class tampering.

Q: How to break parent delegation?

Custom classloader overrides loadClass():

  @Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
    if (name.startsWith("com.mycompany.plugin.")) {
        return findClass(name);  // load locally, skip parent
    }
    return super.loadClass(name, resolve);
}
  

Used in: OSGi, Tomcat (web app isolation), plugin architectures.

JIT Compilation

Q: How does JIT work?

  Bytecode → Interpreter (slow) → Hot methods detected → JIT compile to native code → Execute native
  

Tiered compilation (Java 7+):

  1. Interpret
  2. C1 (client) compiler — fast compile, moderate optimization
  3. C2 (server) compiler — slow compile, aggressive optimization

Hot methods identified by invocation counters.

Common Scenario Questions

Q: OutOfMemoryError in production — how to diagnose?

  1. Check error type (heap, metaspace, direct memory, threads)
  2. Analyze heap dump with Eclipse MAT
  3. Look for leak suspects, dominator tree
  4. Check GC logs for frequent Full GC
  5. Review recent code changes (new caches, unclosed resources)

Q: How would you reduce GC pause times?

  1. Switch to ZGC or G1 with lower MaxGCPauseMillis
  2. Reduce object allocation rate
  3. Increase heap size if old gen is consistently full
  4. Fix memory leaks causing premature Full GC
  5. Use object pooling for frequently allocated objects