Profile Photo

Java internal working

Created on: Sep 19, 2024

java internal working Let's understand java internal working with hello world program. We will looks what happens internally behind the program.

Let's create a file Test.java and write below program.

public class Test { public static void main(String[] args) { System.out.println("Hello world"); } }

java code can't be directed executed, it has to be compiled into bytecode. This will produce a file with .class extension which is bytecode. bytecode is a middle code between human-readable code and machine code. It is platform-independent and is saved in a .class file.

javac Test.java

Let's run the code.

java Test

For below code,below process happens

  1. Class Loading: Java Virtual Machine (JVM) loads Test.class code in memory which is primarily RAM.
  2. Bytecode Verification: JVM performs bytecode verification process to ensure the bytecode does not violate any security constraints. It checks for issues like stack overflows or illegal data access, memory corruption, illegal instructions
  3. Conversion: Just-In-Time(JIT) which is a part of JVM translates the bytecode into machine code that can be directly executed by the host machine.
  4. Execution: JVM looks for main() method, and starts executing the code.
  5. After execution, JVM terminates.

Important points:

  1. JVM is only specification and its has various implementation. Some of its implementation are OpenJDK, Oracle JDK, Zulu JDK

Class Loader Subsystem:

Here’s what the Class Loader Subsystem does in plain terms:

  1. Loads Classes:
    It finds the .class files you need (like from your project, external libraries, or Java's built-in classes) and loads them into the JVM so they can be used. Java has different types of class loaders:

    • Bootstrap Class Loader: Loads core Java classes (like java.util., java.lang.).
    • Extension Class Loader: Loads classes from the Java extensions directory.
    • Application Class Loader: Loads classes from your application's code and libraries.
  2. Links Classes: After loading, it links the class by:

    • Verifying: Ensuring the bytecode is valid and follows Java's rules (to prevent errors or security risks).
    • Preparing: Reserving memory for variables and setting them to default values.
    • Resolving: Connecting references in the class to their actual implementations.
  3. Initializes Classes:
    Once everything is ready, it runs the static blocks or initializes static variables in the class.

Runtime data area

Runtime Data Area
├── Method Area (shared)
├── Heap (shared)
├── Thread 1:
│   ├── Java Stack
│   ├── PC Register
│   ├── Native Method Stack
├── Thread 2:
│   ├── Java Stack
│   ├── PC Register
│   ├── Native Method Stack
  1. Method Area:

    • Stores metadata about classes loaded by the JVM, including:
      • Class names
      • Method code (bytecode)
      • Field information
      • Static variables
      • Runtime Constant Pool (used for literals like final constants and method references)
    • Shared among all threads.
  2. Heap:

    • Stores all Java objects and their instance variables.
    • Shared among all threads.
    • Garbage collection happens here to reclaim memory from objects no longer in use.
  3. Stack:

    • Holds method-specific data such as:
      • Local variables
      • Method call information (stack frames)
      • Results of intermediate operations.
    • Each thread has its own stack.
    • Operates in a Last In, First Out (LIFO) manner.
  4. PC Register (Program Counter Register):

    • Keeps track of the address of the JVM instruction currently being executed for each thread.
    • Each thread has its own PC register.
  5. Native Method Stack:

    • Used to manage calls to native (non-Java) methods, written in other programming languages like C or C++.
    • Each thread has its own native method stack.

Execution Engine

  1. Bytecode Interpretation:

    • Converts Java bytecode (platform-independent) into platform-specific machine code, instruction by instruction.
    • Historically slower since each instruction is interpreted at runtime.
  2. Just-In-Time (JIT) Compilation:

    • Converts bytecode into machine code in larger chunks (e.g., methods or loops) and caches it for reuse.
    • Makes execution faster compared to interpretation.
    • The JIT compiler optimizes frequently executed code paths.
  3. Native Method Execution:

    • Handles calls to native methods (non-Java code, e.g., written in C or C++).
    • Uses the Native Method Interface (JNI) to interact with native libraries.
  4. Garbage Collection (GC):

    • Reclaims memory occupied by objects no longer in use in the heap.

Diagram

architecture diagram

Hardware and Operating System:

  1. JVM relies on operating system to manage system resource like CPU, memory and file system.
  2. The JVM uses the Java Native Interface (JNI) to interact with native libraries provided by the operating system or third-party vendors.
  3. The operating system handles system calls for tasks such as networking, file I/O, and memory management, which the JVM invokes as needed.

References: