Lesson Completion
Back to course

Memory Profiling and Analysis: Finding Memory Issues

Beginner
12 minutes4.7Java

1. The Hook (The "Byte-Sized" Intro)

  • In a Nutshell: Memory profiling = analyzing heap usage to find leaks/inefficiencies.
  • Tools: JVisualVM (free, bundled), Eclipse MAT (heap dump analysis), JProfiler/YourKit (commercial). Heap dump = snapshot of heap memory.
  • Create: -XX:+HeapDumpOnOutOfMemoryError or jmap -dump.
  • MAT features: Dominator tree (what holds memory), leak suspects (suspects report), histogram (object counts), shallow vs retained size.
  • Golden metric: Retained size = total memory freed if object GC'd!

Think of home inspection. Heap dump = blueprint of house. MAT = inspector finding structural issues. Dominator tree = load-bearing walls (remove wall → whole section collapses). Leak suspects = "This room accumulates junk!" Histogram = inventory (200 chairs? Why?)!


2. Conceptual Clarity (The "Simple" Tier)

💡 The Analogy

  • Heap dump: Photo of messy room
  • Dominator tree: Main culprits holding space
  • Shallow size: Object itself
  • Retained size: Object + everything it holds

3. Technical Mastery (The "Deep Dive")

Memory Profiling Tools

ToolTypeBest For
JVisualVMLive monitorReal-time monitoring
Eclipse MATHeap analyzerDeep leak analysis
JConsoleLive monitorJMX monitoring
YourKitCommercialAdvanced profiling
JProfilerCommercialAdvanced profiling

4. Interactive & Applied Code

bash
# ======================================== # CREATING HEAP DUMPS # ======================================== # Automatic on OOM java -XX:+HeapDumpOnOutOfMemoryError \ -XX:HeapDumpPath=/tmp/heap.hprof \ -jar app.jar # Manual with jmap jmap -dump:live,format=b,file=heap.hprof <pid> # Find PID jps # ======================================== # ANALYZING WITH ECLIPSE MAT # ======================================== # 1. Open heap.hprof in MAT # 2. Run "Leak Suspects" report # 3. Check "Dominator Tree" # 4. Look at "Histogram"

Java code for memory monitoring:

java
import java.lang.management.*; import java.util.*; public class MemoryProfilingDemo { public static void main(String[] args) { demonstrateMemoryMonitoring(); demonstrateMemoryPools(); demonstrateGCStats(); } // Basic memory monitoring static void demonstrateMemoryMonitoring() { MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); System.out.println("=== MEMORY USAGE ==="); MemoryUsage heapUsage = memoryBean.getHeapMemoryUsage(); System.out.println("Heap:"); printMemoryUsage(heapUsage); MemoryUsage nonHeapUsage = memoryBean.getNonHeapMemoryUsage(); System.out.println("\nNon-Heap:"); printMemoryUsage(nonHeapUsage); } static void printMemoryUsage(MemoryUsage usage) { System.out.println(" Init: " + usage.getInit() / 1024 / 1024 + " MB"); System.out.println(" Used: " + usage.getUsed() / 1024 / 1024 + " MB"); System.out.println(" Committed: " + usage.getCommitted() / 1024 / 1024 + " MB"); System.out.println(" Max: " + usage.getMax() / 1024 / 1024 + " MB"); } // Memory pools (Eden, Survivor, Old, etc.) static void demonstrateMemoryPools() { System.out.println("\n=== MEMORY POOLS ==="); List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans(); for (MemoryPoolMXBean pool : pools) { System.out.println("\n" + pool.getName() + ":"); System.out.println(" Type: " + pool.getType()); MemoryUsage usage = pool.getUsage(); System.out.println(" Used: " + usage.getUsed() / 1024 / 1024 + " MB"); System.out.println(" Max: " + usage.getMax() / 1024 / 1024 + " MB"); } } // GC statistics static void demonstrateGCStats() { System.out.println("\n=== GC STATISTICS ==="); List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean gcBean : gcBeans) { System.out.println("\n" + gcBean.getName() + ":"); System.out.println(" Collections: " + gcBean.getCollectionCount()); System.out.println(" Time: " + gcBean.getCollectionTime() + " ms"); System.out.println(" Avg: " + (gcBean.getCollectionTime() / Math.max(1, gcBean.getCollectionCount())) + " ms"); } } } // Trigger OOM for heap dump class OOMDemo { public static void main(String[] args) { List<byte[]> list = new ArrayList<>(); try { while (true) { list.add(new byte[1024 * 1024]); // 1MB } } catch (OutOfMemoryError e) { System.out.println("OOM! Heap dump created"); // Analyze heap.hprof with MAT } } }

5. The Comparison & Decision Layer

MetricMeaning
Shallow sizeObject size only
Retained sizeObject + all it retains
DominatorObject removal frees dominated objects

6. The "Interview Corner" (The Edge)

The "Killer" Interview Question: "Shallow vs Retained size?" Answer:

  • Shallow size: Size of object itself (header + fields)
  • Retained size: Shallow + all objects only reachable through it
text
Object A (10 bytes) → Object B (20 bytes) → Object C (30 bytes) ↘ Object D (40 bytes) Shallow size of A: 10 bytes (just A) Retained size of A: 10+20+30+40 = 100 bytes (A + B,C,D only reachable via A) If A is GC'd → 100 bytes freed!

Pro-Tip: MAT Leak Suspects:

text
Leak Suspects Report finds: 1. Objects with large retained size 2. Collections that keep growing 3. ClassLoaders not unloaded 4. Thread locals holding data Common suspects: - Static collections (never cleared) - Caches (unbounded) - Listeners (not removed)

Topics Covered

Java Fundamentals

Tags

#java#programming#beginner-friendly

Last Updated

2025-02-01