1. The Hook (The "Byte-Sized" Intro)
In a Nutshell: Advanced memory topics: (1) Cleaner API (Java 9+, replaces finalize(), explicit cleanup), (2) OutOfMemoryError types (Heap, Metaspace, GC Overhead, Direct Buffer), (3) Escape Analysis (JIT optimization, stack allocation, scalar replacement), (4) Compressed Oops (pointer compression for heaps <32GB, saves 20-30% memory), (5) Off-heap memory (DirectByteBuffer, outside JVM heap). Cleaner = better than finalize() (predictable). OOME = diagnose with heap dumps. Escape Analysis = compiler magic (allocate on stack if possible). Compressed Oops = automatic <32GB!
Think of advanced home features. Cleaner API = smart home (scheduled cleanup). OOME = house full (diagnose: too much stuff vs too small house). Escape Analysis = temporary table (use/discard vs permanent furniture). Compressed Oops = zip compression (more space in same area). Off-heap = storage unit (outside main house)!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy
- Cleaner API: Scheduled cleaning service (vs hoping someone cleans)
- Escape Analysis: Temporary booth (vs permanent store)
- Compressed Oops: Zip file (save space)
- Off-heap: External storage (not in main house)
3. Technical Mastery (The "Deep Dive")
Advanced Topics Overview
| Topic | Java Version | Purpose |
|---|---|---|
| Cleaner API | 9+ | Resource cleanup (replaces finalize) |
| Escape Analysis | All (JIT) | Stack allocation optimization |
| Compressed Oops | All | Pointer compression (<32GB heap) |
| Off-heap | All | Direct memory (outside heap) |
4. Interactive & Applied Code
import java.lang.ref.Cleaner;
import java.nio.ByteBuffer;
public class AdvancedMemoryDemo {
public static void main(String[] args) {
demonstrateCleanerAPI();
demonstrateEscapeAnalysis();
demonstrateOOMTypes();
demonstrateOffHeap();
}
// 1. Cleaner API (Java 9+, better than finalize)
static class Resource implements AutoCloseable {
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
static class State implements Runnable {
// Cleanup logic (must not reference Resource!)
@Override
public void run() {
System.out.println("Cleaning up resource");
// Close file, release memory, etc.
}
}
Resource() {
State state = new State();
this.cleanable = cleaner.register(this, state);
}
@Override
public void close() {
cleanable.clean(); // Explicit cleanup
}
}
static void demonstrateCleanerAPI() {
System.out.println("=== CLEANER API ===");
// ✅ With try-with-resources (explicit)
try (Resource r = new Resource()) {
// Use resource
} // clean() called automatically
// ⚠️ Without try-with-resources (relies on GC)
Resource r2 = new Resource();
r2 = null;
System.gc(); // Cleaner invoked when GC'd (not guaranteed timing!)
}
// 2. Escape Analysis demonstration (conceptual)
static void demonstrateEscapeAnalysis() {
System.out.println("\n=== ESCAPE ANALYSIS ===");
// Object doesn't escape method → may be stack-allocated!
Point p = new Point(10, 20);
int sum = p.x + p.y;
System.out.println("Sum: " + sum);
// JVM may allocate 'p' on stack (faster, no GC needed!)
// vs returning object (escapes → heap allocation)
Point p2 = createPoint();
// p2 escapes → must be on heap
}
static Point createPoint() {
return new Point(1, 2); // Escapes method
}
static class Point {
int x, y;
Point(int x, int y) { this.x = x; this.y = y; }
}
// 3. OutOfMemoryError types
static void demonstrateOOMTypes() {
System.out.println("\n=== OUT OF MEMORY ERROR TYPES ===");
try {
// Type 1: Heap space
List<byte[]> list = new ArrayList<>();
while (true) {
list.add(new byte[1024 * 1024]); // 1MB
}
} catch (OutOfMemoryError e) {
System.out.println("OOM: " + e.getMessage());
// "Java heap space"
}
// Type 2: Metaspace (loading many classes)
// OutOfMemoryError: Metaspace
// Type 3: GC Overhead Limit
// Spending >98% time in GC, <2% heap recovered
// OutOfMemoryError: GC overhead limit exceeded
// Type 4: Unable to create native thread
// Too many threads
// OutOfMemoryError: unable to create new native thread
// Type 5: Direct buffer memory
// ByteBuffer.allocateDirect() exceeds limit
// OutOfMemoryError: Direct buffer memory
}
// 4. Off-heap memory (DirectByteBuffer)
static void demonstrateOffHeap() {
System.out.println("\n=== OFF-HEAP MEMORY ===");
// Heap-allocated buffer
ByteBuffer heapBuffer = ByteBuffer.allocate(1024);
System.out.println("Heap buffer: " + heapBuffer.isDirect()); // false
// Off-heap buffer (direct memory)
ByteBuffer directBuffer = ByteBuffer.allocateDirect(1024);
System.out.println("Direct buffer: " + directBuffer.isDirect()); // true
// Benefits:
// - Faster I/O (no copy to native memory)
// - Not subject to GC pauses
// - Shared with native code
// Drawbacks:
// - Slower allocation
// - Manual cleanup (or GC cleanup, but unpredictable)
// - Limited by -XX:MaxDirectMemorySize
}
}
/*
JVM FLAGS FOR ADVANCED TOPICS:
# Cleaner API (no flags, built-in)
# Escape Analysis (enabled by default)
-XX:+DoEscapeAnalysis # Enable (default)
-XX:-DoEscapeAnalysis # Disable
# Compressed Oops (automatic for heap <32GB)
-XX:+UseCompressedOops # Enable (default if heap <32GB)
-XX:-UseCompressedOops # Disable
# Saves ~20-30% memory by compressing 64-bit pointers to 32-bit
# Off-heap Memory
-XX:MaxDirectMemorySize=1g # Limit direct buffer memory
# OutOfMemoryError actions
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/tmp/heap.hprof
-XX:OnOutOfMemoryError="kill -9 %p" # Kill process on OOM
*/5. The Comparison & Decision Layer
| finalize() | Cleaner API |
|---|---|
| Deprecated (Java 9+) | Recommended |
| Unpredictable timing | More predictable |
| Performance issues | Better performance |
| Resurrection possible | No resurrection |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "What is Escape Analysis?" Answer: JIT compiler optimization that determines if object escapes method scope!
// Object DOESN'T escape → stack allocation possible
void method1() {
Point p = new Point(1, 2);
int sum = p.x + p.y;
// p used only in method → JVM may allocate on STACK!
// Faster, no GC needed
}
// Object ESCAPES → heap allocation required
Point method2() {
Point p = new Point(1, 2);
return p; // Escapes! Must be on HEAP
}Benefits:
- Stack allocation (faster)
- Scalar replacement (eliminate object, use fields directly)
- Lock elision (remove unnecessary locks)
Pro-Tips:
- Compressed Oops:
Heap <32GB:
- 64-bit pointers compressed to 32-bit
- Saves ~20-30% memory
- Automatic (no flag needed)
Heap ≥32GB:
- Compression disabled
- Full 64-bit pointers
- More memory overhead
Sweet spot: 31GB heap (compression enabled)- OutOfMemoryError diagnosis:
# Heap space → increase heap or fix leak
java -Xmx4g -jar app.jar
# Metaspace → loading too many classes
java -XX:MaxMetaspaceSize=512m -jar app.jar
# Direct buffer → increase direct memory
java -XX:MaxDirectMemorySize=1g -jar app.jar
# Always get heap dump:
-XX:+HeapDumpOnOutOfMemoryError