Fundamentals 52 min read

Understanding JVM Bytecode, JIT Compilation, and Garbage Collection

The article explains how the JVM executes Java bytecode, detailing bytecode structure, lambda compilation, JIT tiers and optimizations such as inlining and escape analysis, describes runtime memory areas and generational garbage collectors—including G1, ZGC, and Shenandoah—and offers key tuning flags for balancing throughput, latency, and heap size.

DeWu Technology
DeWu Technology
DeWu Technology
Understanding JVM Bytecode, JIT Compilation, and Garbage Collection

The Java Virtual Machine (JVM) is a virtual computer that runs Java bytecode. By implementing the JVM specification on a specific hardware platform, any compiled Java program can be executed on that system.

This article extracts several core topics of the JVM, including bytecode, the Just‑In‑Time (JIT) compiler, runtime data areas, object memory layout, and garbage collection strategies.

Bytecode

Bytecode consists of an opcode (1 byte) optionally followed by operands. Most JVM instructions have no operands, which keeps the instruction set within 256 entries.

Example of a simple bytecode interpreter loop:

do{<br/>    // fetch opcode from program counter<br/>    // if operand exists, fetch it<br/>    // execute the operation defined by the opcode<br/>} while (next instruction exists);

Common instruction categories include loading/storing, control transfer, object manipulation, method invocation (invoke*), arithmetic, synchronization, and exception handling.

Lambda Expressions and Bytecode

Lambda expressions are compiled into synthetic methods and runtime‑generated classes. Example:

public static void func1(int localInt) {<br/>    Action0 add10 = () -> System.out.println(localInt + 10);<br/>}

After compilation the lambda is transformed into:

public static void func1(int localInt) {<br/>    Action0 add10 = Main$$Lambda$1.get$Lambda(localInt);<br/>}<br/><br/>private static /*synthetic*/ void lambda$func1$0(int localInt) {<br/>    System.out.println(localInt + 10);<br/>}<br/><br/>final class Main$$Lambda$1 implements Action0 {<br/>    private final int arg$1;<br/>    private Main$$Lambda$1(int v) { this.arg$1 = v; }<br/>    public void call() { Main.lambda$func1$0(this.arg$1); }<br/>}

JIT Compilation

JIT compiles hot methods into native code at runtime, improving performance over pure interpretation. The HotSpot VM uses multiple compilation tiers:

Tier 0 – interpreter.

Tier 1 – client (c1) compilation without profiling.

Tier 2 – client compilation with profiling.

Tier 3 – client compilation with full profiling.

Tier 4 – server (c2) compilation with aggressive optimizations.

Hot methods are first interpreted; after a threshold (≈1500 executions for c1, ≈10000 for c2) they are compiled. Flags such as -Xint, -client, and -server control the mode.

Method Inlining

Small methods (e.g., getters/setters) are inlined by the JIT to eliminate call overhead. Virtual method inlining uses class‑hierarchy analysis (CHA) and inline caches to ensure correctness when new subclasses appear.

Escape Analysis

Escape analysis determines whether an object can be allocated on the stack or scalar‑replaced, reducing heap pressure. It classifies objects as non‑escaping, method‑escaping, or thread‑escaping.

Runtime Data Areas

The JVM defines several memory regions: program counter, JVM stack, native method stack, heap, method area, and runtime constant pool. The heap is further divided into generations (young, old, and humongous) and managed by various garbage collectors.

Garbage Collection

GC algorithms include:

Mark‑Sweep

Mark‑Compact

Mark‑Copy

Modern collectors (Serial, Parallel, CMS, G1, ZGC, Shenandoah) differ in parallelism, concurrency, and pause‑time characteristics. G1, for example, partitions the heap into regions, uses Remembered Sets (card tables) to track inter‑region references, and performs Young GC (YGC) and mixed GC cycles.

Typical G1 workflow:

Stop‑the‑world pause.

Select collection set (CSet) – usually all young regions.

Root scanning (including RSet entries).

Copy live objects, update references.

Process soft/weak/phantom references.

Clear card tables and rebuild RSet.

Trigger concurrent marking if old‑generation occupancy exceeds -XX:InitiatingHeapOccupancyPercent.

Common JVM Parameters

Key flags for tuning include -Xms, -Xmx, -XX:+UseG1GC, -XX:MaxGCPauseMillis, -XX:G1HeapRegionSize, -XX:InitiatingHeapOccupancyPercent, and -XX:+UseStringDeduplication. Proper tuning balances memory size, throughput, and latency.

The article concludes with a reminder that JVM tuning is workload‑specific and that most applications benefit from larger heaps, high throughput, and low pause times, often sacrificing one of these goals for the others.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaJVMperformancebytecodeGarbage CollectionJIT
DeWu Technology
Written by

DeWu Technology

A platform for sharing and discussing tech knowledge, guiding you toward the cloud of technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.