JVM Internals & Memory — Cheat Sheet
Java A–Z · 5 topics. Download the PDF or the Instagram carousel and share it.
Cheat Sheet · AiCanCode.org
JVM Internals & Memory
Java A–Z5 topicsQuick revision reference
1
JVM Architecture
- ✓Class loading: Loading → Linking (Verify/Prepare/Resolve) → Initialisation.
- ✓Bootstrap → Platform → Application class loaders form the delegation chain.
- ✓Heap: shared object storage. Stack: per-thread method frames. Metaspace: class metadata (off-heap).
- ✓JIT compiles hot methods to native code; Tiered Compilation uses C1 then C2.
- ✓StackOverflowError = stack full; OutOfMemoryError = heap or Metaspace full.
ClassLoaders.java
// Inspect class loaders
Class<?> cls = String.class;
System.out.println(cls.getClassLoader()); // null = Bootstrap
Class<?> userCls = MyApp.class;
ClassLoader appLoader = userCls.getClassLoader();
System.out.println(appLoader); // AppClassLoader
System.out.println(appLoader.getParent()); // PlatformClassLoader
System.out.println(appLoader.getParent().getParent()); // null (Bootstrap)
// Force class loading
Class<?> loaded = Class.forName("com.example.SomeService");
// Triggers: Loading → Linking → Initialisation
// Lazy loading — class loaded only when first used
// JVM loads a class the first time its bytecode is needed
// Custom class loader
public class HotReloadLoader extends ClassLoader {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = loadBytecodeFromDisk(name);
return defineClass(name, bytes, 0, bytes.length);
}
}2
Garbage Collection
- ✓Generational hypothesis: most objects die young — GC exploits this with Eden/Survivor/Old.
- ✓Minor GC collects Young Gen (fast); Full GC collects everything (slow — minimize it).
- ✓G1GC: region-based, meets pause time target, default since Java 9.
- ✓ZGC: sub-millisecond pauses, concurrent relocation, ideal for latency-critical large heaps.
- ✓Common memory leaks: unclosed resources, static collections, ThreadLocal without remove(), inner class references.
GCOverview.java
/*
Object lifecycle in generational GC:
new Object()
│
▼
┌─────────┐ Minor GC ┌──────┐ N GCs ┌──────────┐
│ Eden │ ─────────► │ S0/S1│ ───────► │ Old Gen │
└─────────┘ └──────┘ └──────────┘
Most objects Survivors Long-lived
die here bounce S0↔S1 objects
(very fast GC) (age threshold) (expensive GC)
*/
// GC tuning flags
// -Xms512m — initial heap size
// -Xmx2g — maximum heap size
// -Xmn512m — Young Gen size
// -XX:+UseG1GC — use G1 collector (default Java 9+)
// -XX:+UseZGC — use ZGC (Java 15+, sub-ms pauses)
// -XX:MaxGCPauseMillis=200 — G1 pause time target
// -XX:+PrintGCDetails — verbose GC logging
// -Xlog:gc*:file=gc.log — GC log to file (Java 9+)3
JVM Tuning and Profiling
- ✓Set -Xms equal to -Xmx to avoid heap resize pauses in production.
- ✓Always enable -XX:+HeapDumpOnOutOfMemoryError and -XX:+ExitOnOutOfMemoryError.
- ✓jcmd is the preferred tool for live diagnostics — heap dumps, thread dumps, JFR control.
- ✓JFR has ~1% overhead — safe for continuous production profiling.
- ✓Allocation pressure and lock contention are the two most common Java performance bottlenecks.
JvmFlags.sh
# Production JVM flags template # Heap sizing -Xms4g -Xmx4g # fixed heap — avoids resizing pauses -XX:+UseG1GC # G1GC (default Java 9+) -XX:MaxGCPauseMillis=100 # target max pause # GC logging (Java 9+ unified logging) -Xlog:gc*:file=/logs/gc.log:time,level,tags:filecount=5,filesize=20m # Diagnostics -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/heap-$(date +%s).hprof -XX:+ExitOnOutOfMemoryError # restart rather than limp on # JFR continuous profiling (low overhead ~1%) -XX:StartFlightRecording=filename=recording.jfr,settings=profile,duration=60s # Metaspace -XX:MetaspaceSize=256m # initial Metaspace commit size -XX:MaxMetaspaceSize=512m # cap to prevent unbounded growth
4
Java Memory Model (JMM)
- ✓JMM defines happens-before: if A HB B, all effects of A are visible when B executes.
- ✓Volatile write HB subsequent volatile read — ensures visibility without locking.
- ✓Synchronized unlock HB subsequent lock of the same monitor.
- ✓final fields are safely published after constructor completes — no synchronisation needed.
- ✓Safe publication: use volatile, final, synchronized, or concurrent collections to share objects.
VisibilityBug.java
// Classic visibility bug (may loop forever)
class BrokenStop {
static boolean stop = false; // no volatile
public static void main(String[] args) throws InterruptedException {
new Thread(() -> {
while (!stop) {} // JIT may hoist 'stop' read out of the loop
System.out.println("stopped");
}).start();
Thread.sleep(100);
stop = true; // write may never be flushed to main memory
// or the reader thread may never see it
}
}
// Why this can fail:
// 1. JIT compiler can cache 'stop' in a register (loop invariant hoisting)
// 2. CPU write buffer may not flush to main memory
// 3. Reader CPU cache may not invalidate its cached copy
// Fix: declare stop as volatile — establishes happens-before5
Class Loading and Hot Reload
- ✓Class identity = fully-qualified name + ClassLoader — same name, different loaders = different types.
- ✓Parent delegation prevents classpath classes from overriding Bootstrap classes (java.lang.*).
- ✓Hot reload: break parent delegation for target classes, create a new loader, discard the old.
- ✓Class unloading: happens when loader is GC'd — requires no live references to loader or its classes.
- ✓Metaspace leaks: typically caused by class loader leaks (dynamic proxies, runtime code generation).
LoaderIdentity.java
// Two loaders — two identities
ClassLoader loader1 = new URLClassLoader(urls);
ClassLoader loader2 = new URLClassLoader(urls);
Class<?> cls1 = loader1.loadClass("com.example.Plugin");
Class<?> cls2 = loader2.loadClass("com.example.Plugin");
System.out.println(cls1 == cls2); // FALSE — different identities!
// ClassCastException across loaders
Object obj = cls1.getDeclaredConstructor().newInstance();
// com.example.Plugin cast = (com.example.Plugin) obj;
// ^ ClassCastException if Plugin was loaded by the app loader
// but obj was loaded by loader1
// Check which loader loaded a class
System.out.println(String.class.getClassLoader()); // null (Bootstrap)
System.out.println(ArrayList.class.getClassLoader()); // null (Bootstrap)
System.out.println(MyService.class.getClassLoader()); // AppClassLoaderLearn this free with Aria, your AI tutor → AiCanCode.org/learn/java