Bytecode & Runtime Data Areas
Java source compiles to platform-neutral bytecode (.class files). The JVM runtime is partitioned into: heap (objects), method area/Metaspace (class metadata), JVM stack (one per thread, holds stack frames), PC register (per thread), and native method stack.
Bytecode = universal recipe card. The JVM kitchen (any OS) can cook it. Stack = each chef's personal cutting board. Heap = the shared pantry. Metaspace = the recipe binder on the shelf.
Each stack frame contains local variable array, operand stack, and reference to the runtime constant pool. The method area (Metaspace since Java 8, moved out of heap) stores class structures, method bytecode, and static variables. Metaspace grows dynamically by default (bounded by -XX:MaxMetaspaceSize). The heap is divided into young (Eden + two Survivor spaces) and old generation. Bytecode instructions include: aload/astore (reference), iload/istore (int), invoke variants (invokevirtual, invokestatic, invokeinterface, invokespecial, invokedynamic).
invokedynamic (introduced in Java 7, used by lambdas and MethodHandles) defers method dispatch linkage to a bootstrap method at first call, enabling efficient implementation of lambdas, Groovy closures, and dynamic languages on the JVM. The JVM spec defines the verifier which checks bytecode for type safety before execution. StackMapTable attributes (Java 6+) allow the verifier to do a single-pass type inference instead of fixed-point iteration. Tools like ASM and ByteBuddy manipulate bytecode at this level — heavily used by frameworks like Hibernate, Spring, and Mockito for runtime code generation.
Java compiles to stack-based bytecode that is platform-neutral. The JVM runtime is divided into heap (objects, GC-managed), Metaspace (class metadata, outside heap since Java 8), and per-thread areas: JVM stack (stack frames with local vars and operand stack) and PC register. Key bytecode instruction families are invokevirtual for instance methods, invokestatic for static methods, invokeinterface for interface calls, and invokedynamic for lambdas and runtime-linked dispatch.
PermGen was replaced by Metaspace in Java 8 — PermGen OOM errors no longer exist, but Metaspace can still OOM if class loading is unbounded (e.g., CGLib proxy generation loops) unless -XX:MaxMetaspaceSize is set.