Java's reputation rests on the famous "Write Once, Run Anywhere" principle, and that promise is delivered by a layered software stack. The Java Virtual Machine (JVM) is an abstract computing machine that executes Java bytecode rather than native machine instructions. When you compile a Java source file with javac, you produce .class files containing platform-neutral bytecode. The JVM, sitting between the bytecode and the underlying operating system, translates instructions into native code at run time. The three-tier JDK ⊃ JRE ⊃ JVM relationship makes the division of responsibilities clear: the JDK (Java Development Kit) bundles the compilers and tools developers need, the JRE (Java Runtime Environment) supplies the standard libraries and JVM needed to run applications, and the JVM is the runtime engine that actually executes bytecode.
Internally, the JVM divides memory into regions with very different performance characteristics. Every thread gets its own LIFO stack of stack frames, where local variables (primitives and object references) and the operand stack live; stack allocation is extremely fast and memory is freed automatically when a method returns. All objects and class metadata live in the heap, which is shared and garbage-collected, organized into generational regions (Eden, Survivor, Old/Tenured) under the HotSpot JVM. Beyond heap and stacks, HotSpot reserves Metaspace (native memory for class metadata, replacing PermGen in Java 8), a code cache for JIT-compiled native instructions, direct memory used by NIO ByteBuffer.allocateDirect for off-heap allocations, and compressed oops that let 64-bit JVMs use 32-bit object references when the heap is under 32 GB. Stack size is tuned with -Xss, while heap size is bounded by -Xms and -Xmx.
Garbage collection is the JVM's automatic mechanism for reclaiming heap memory held by unreachable objects. Objects become GC-eligible when no live reference points to them, but the JVM provides only one non-deterministic knob (System.gc() is a hint, not a command). Different collectors serve different service-level agreements: Parallel GC maximizes throughput at the cost of stop-the-world pauses, G1 (the default since Java 9) balances latency and throughput by collecting regions concurrently toward a target pause time (-XX:MaxGCPauseMillis), and ZGC (since Java 11) achieves sub-millisecond pauses regardless of heap size, making it ideal for very large multi-GB heaps. The legacy Object.finalize() method, called at most once before an object is reclaimed, has been deprecated for removal; modern code prefers try-with-resources for deterministic cleanup and java.lang.ref.Cleaner (Java 9+) for cleaning off-heap resources via a daemon-thread action registered against the target object.
To balance memory pressure with caching, Java defines four reference strengths. Strong references are the normal Object o = new Object() form, which keep objects reachable and prevent collection. SoftReference objects are cleared only when the JVM is under memory pressure, making them well suited to memory-sensitive caches. WeakReference objects are cleared at the next garbage collection cycle; the canonical use is WeakHashMap, where an entry vanishes automatically once its key is no longer strongly reachable (though the value's strong reference to back-data must be managed carefully to avoid resurrection). PhantomReference objects are enqueued after the object's finalizer has run but before the memory is reclaimed, and are used to schedule post-mortem cleanup actions. The execution model itself also adapts at run time: hot methods are detected by the JIT compiler (C1/C2 in HotSpot, Graal in newer versions) and translated into native machine code, with tiered compilation balancing fast startup against steady-state speed, while AOT compilation via GraalVM Native Image produces standalone binaries with near-instant startup and lower memory at the cost of slower peak CPU and less reflection-friendly behavior. A .class file's structure mirrors this duality: starting with the magic 0xCAFEBABE, it carries minor/major version, a constant pool of UTF-8 literals and references, access flags, this/super class pointers, interface list, fields, methods, and attributes (code, line numbers, generic signatures, annotations) – the binary contract that the JVM parses on load.