1.2 Java under the hood Flashcards
(41 cards)
What happens during Java compilation?
javac compiles .java source files into .class bytecode files. The process includes syntax checking, type checking, and generating platform-independent bytecode using stack-based instruction set (opcodes like iload, istore, iadd, invokevirtual).
What is Java bytecode and why is it important?
Bytecode is an intermediate representation between source code and machine code. It’s platform-independent, uses stack-based architecture, and allows “write once, run anywhere.” Bytecode gets verified for type safety and security before execution.
What are the three phases of bytecode verification?
1)Verification - ensures type safety and prevents buffer overflows,
2) Preparation - allocates memory for static variables,
3) Resolution - converts symbolic references to direct references.
What’s the relationship between JDK, JRE, and JVM?
JDK contains JRE + development tools (javac, javadoc, jar).
JRE contains JVM + core libraries + supporting files.
JVM is the runtime engine that executes bytecode.
Think: JDK ⊃ JRE ⊃ JVM.
What components make up the JRE?
JVM (execution engine), Core Libraries (java.lang, java.util, etc.), Native Method Interface (JNI), and supporting configuration files and resources needed for runtime execution.
Explain the three-tier class loading delegation model
1) Bootstrap ClassLoader - loads core Java classes (java.lang.), implemented in native code,
2) Extension ClassLoader - loads extension libraries from ext directory,
3) Application ClassLoader - loads application classpath classes. Child loaders delegate to parent first.*
What are the three phases of class loading?
1) Loading - finds and reads .class file into memory
2) Linking - verification, preparation, and resolution of symbolic references
3) Initialization - executes static initializers and static variable assignments.
When does class initialization occur?
When first instance is created, static method is called, static field is accessed (except compile-time constants), class is explicitly loaded via reflection, or when initializing a subclass.
Describe the generational heap structure
Young Generation: Eden space (new objects) + two Survivor spaces (S0, S1).
Old Generation: Tenured space for long-lived objects.
Objects start in Eden, survive to Survivor spaces, then get promoted to Old Gen after multiple GC cycles.
What is the generational hypothesis and why does it matter?
Most objects die young, so separating generations optimizes GC. Minor GC occurs frequently in Young Gen (fast), Major GC occurs less frequently in Old Gen (slower). This reduces overall GC overhead.
What happens during object allocation in the heap?
New objects allocated in Eden space. When Eden fills, Minor GC runs. Surviving objects move to Survivor space. After several GC cycles, long-lived objects promote to Old Generation (tenured space).
What is Metaspace and how does it differ from PermGen?
Metaspace (Java 8+) stores class metadata in native memory, replacing PermGen. Unlike PermGen’s fixed size causing OutOfMemoryErrors, Metaspace grows dynamically and is limited only by available native memory.
Explain the structure of each thread’s stack
Each thread has its own stack containing method call frames. Each frame includes: local variable array, operand stack for intermediate calculations, and reference to the constant pool of the current class.
What are the PC Register and Native Method Stack?
PC Register: stores address of currently executing instruction for each thread.
Native Method Stack: handles native method calls through JNI, separate from regular Java method stack
How does the HotSpot JVM’s tiered compilation work?
Initially, interpreter executes bytecode (quick startup). When methods become “hot” (frequently called), C1 compiler provides fast compilation with basic optimizations. For long-running hot code, C2 compiler applies aggressive optimizations.
What triggers JIT compilation?
A: Method call counters and loop back-edge counters. When thresholds are exceeded, methods marked as “hot spots.” Profiling data collected during interpretation guides optimization decisions in compiled code.
Name 5 major JIT compiler optimizations
1) Inlining - replaces method calls with method body,
2) Escape Analysis - stack-allocates non-escaping objects,
3) Dead Code Elimination - removes unreachable code, 4) Loop Unrolling - reduces loop overhead, 5) Vectorization - uses SIMD instructions.
What is escape analysis and how does it optimize performance?
A: Determines if objects escape method scope. Non-escaping objects can be stack-allocated instead of heap-allocated, eliminating GC pressure and improving cache locality. Can also eliminate synchronization on non-escaping objects.
How does method inlining improve performance?
Eliminates method call overhead, enables further optimizations on larger code blocks, improves instruction cache locality, and allows better register allocation across formerly separate methods.
What is deoptimization in the JIT compiler?
When runtime assumptions used for optimization prove false, JIT “deoptimizes” - falls back to interpreter or recompiles with different assumptions. Examples: type speculation fails, class hierarchy changes.
Explain the Mark-Sweep-Compact algorithm
1) Mark - traverse object graph from GC roots, marking reachable objects,
2) Sweep - deallocate unmarked (dead) objects,
3) Compact - defragment memory by moving objects together, updating references.
What are GC roots?
Starting points for reachability analysis: static variables, local variables in active methods, JNI global references, objects in native method stacks, and system class loader references.
Compare generational GC strategies
Minor GC - frequent, fast, Young Generation only. Major GC - less frequent, slower, Old Generation.
Full GC - entire heap + Metaspace, slowest but most thorough cleanup.
How does G1GC differ from traditional collectors?
Divides heap into regions instead of generations.
Uses concurrent marking and incremental collection.
Targets specific pause time goals. Better for large heaps (>4GB) requiring low latency.