Understanding JVM Memory Management
A deep dive into Java stack memory, heap memory, metaspace, and how garbage collection actually reclaims objects.
Category
21 articles
A deep dive into Java stack memory, heap memory, metaspace, and how garbage collection actually reclaims objects.
A System.nanoTime() loop around your code is not a benchmark — it's a measurement of the JIT compiler warming up. JMH exists to fix exactly that.
Wildcard generics confuse most developers on sight, but the PECS rule turns a wall of question marks into a mechanical, memorable decision.
HashMap's average O(1) performance depends on assumptions about hash distribution and load factor that are worth understanding before they're violated.
Strings look like the simplest type in Java, but the string pool, compact string encoding, and concatenation strategy all affect memory and speed directly.
A Java memory leak is always a reachability bug. Heap dumps let you find exactly which reference is holding on, instead of guessing at flags.
Guessing at performance problems wastes time twice: once guessing, once confirming the guess was wrong. Here's how to actually see what the JVM is doing.
JPMS is easy to dismiss after a rough first encounter, but used selectively it solves real encapsulation problems the classpath never could.
Optional was designed for exactly one purpose: expressive return types. Used anywhere else, it tends to add ceremony without removing any risk.
Switch expressions with pattern matching turn instanceof chains and type-casting boilerplate into concise, exhaustive, compiler-checked logic.
Beyond synchronized and Thread, java.util.concurrent has a purpose-built tool for nearly every coordination problem. Here's when to reach for each.
Marking fields final is not the same as making a class immutable. Here's what full immutability actually requires and where it usually leaks.
A broken equals or hashCode doesn't crash your program — it quietly corrupts HashMaps and HashSets in ways that only show up much later.
ClassLoaders quietly decide how your code finds classes, why two copies of the same class can coexist, and why app servers leak metaspace.
The JVM doesn't run your bytecode as-is for long. Here's what C1, C2, and tiered compilation actually do, and why your benchmarks lie without warmup.
Most GC tuning advice is cargo culted flags copied from a blog post. Here's how to read the actual signals before you touch anything.
CompletableFuture's API surface is huge and easy to misuse. These are the composition patterns that hold up in real asynchronous pipelines.
Streams read beautifully in code review and hide real performance costs in production. Here are the traps that show up most often and how to avoid them.
Sealed classes let the compiler enforce that you've handled every case, turning a class of runtime bugs into compile-time errors.
Records aren't just less boilerplate — they push Java toward modeling data as data, separate from behavior. Here's how to use them well.
Virtual threads remove the cost of blocking, not the need for careful concurrency design. Here's exactly what improves and what stays your problem.