Core Java With OCJP/SCJP:JVM Architecture Part- 8|| complete jvm architecture
Complete Architecture of JVM
Overview of Java File Compilation
- The session begins with an explanation of the complete architecture of the Java Virtual Machine (JVM), focusing on how a Java file is processed.
- A Java source file, such as
test.java, is compiled using thejavaccommand to generate a Java class file.
- This class file serves as input for the JVM, which is responsible for loading and executing it.
Class Loader Subsystem
- The architecture includes three main modules: Class Loader Subsystem, Memory Areas, and Execution Engine.
- The Class Loader Subsystem has three primary functions: loading, linking, and initialization.
Loading Process
- The loading phase consists of multiple parts: Bootstrap Class Loader, Extension Class Loader, and Application Class Loader.
- These loaders follow an extension delegation algorithm to manage class loading effectively.
Linking Process
- The linking phase involves three activities: verification, preparation, and resolution.
- Verification ensures that the bytecode is valid and adheres to JVM specifications.
- Preparation allocates memory for static variables in classes.
- Resolution connects symbolic references in the code to actual memory locations.
Initialization Phase
- After linking, the initialization phase occurs where static initializers are executed.
- The entire process from loading through initialization is managed by the Class Loader Subsystem.
Memory Areas in JVM
- Various memory areas within the JVM include:
- Method Area: Stores class-level data including metadata about classes.
- Heap Area: Contains object data and instance variables associated with those objects.
Detailed Memory Areas Description
- In the Method Area:
- It holds class data necessary for execution.
- In the Heap Area:
- Object data along with corresponding instance variables are stored here. Static variables related to classes are also kept in this area.
Memory Areas in JVM
Overview of Memory Areas
- The third memory area discussed is the stack area, where a separate runtime stack is created for each thread (T1, T2, ..., Tn).
- Each entry in the stack is referred to as a stack frame, which contains three parts: local variable array, operand stack, and frame data.
- Local variables are stored in the corresponding runtime stack for each thread, emphasizing that every thread has its own dedicated stack.
Program Counter (PC) Registers
- The fourth memory area is the PC register. Each thread has its own PC register to track the address of the currently executing instruction.
- For every thread (T1, T2, ..., Tn), a separate PC register is created to manage execution flow independently.
Native Method Stacks
- The last memory area mentioned is native method stacks, with each thread having its own native method stack by default.
Summary of JVM Memory Areas
- In total, there are four main memory areas within the JVM: method area, heap area, stack area, and native method stacks.
- The method area stores class-level data and static variables; all Java objects reside in the heap area along with instance variables and arrays.
Execution Engine Components
Role of Execution Engine
- The execution engine executes programs loaded into the JVM from class files via the class loader subsystem.
Key Components of Execution Engine
- The execution engine consists mainly of two parts: an interpreter and a JIT compiler.
JIT Compiler Functionality
- The JIT compiler includes several components:
- Intermediate code generator produces intermediate code.
- Code optimizer enhances this intermediate code for efficiency.
- Target code generator converts optimized code into machine or native code.
This structured overview captures key concepts related to memory management within the JVM and highlights essential components of its execution engine.
Execution Engine Components in Java
Overview of the Execution Engine
- The execution engine is a central component of the Java Virtual Machine (JVM), akin to a CPU, responsible for executing programs line by line.
- It includes various components such as the Just-In-Time (JIT) compiler and garbage collector, which enhance performance and manage memory.
JIT Compiler Functionality
- The JIT compiler optimizes performance by generating machine code for frequently called methods, reducing the need for repeated interpretation.
- During execution, the JVM may require native method libraries, which are accessed through the Java Native Interface (JNI).
Class Loading Process
- The class loader subsystem is responsible for loading class files into the JVM. It performs three main activities: loading, linking, and initialization.
Types of Class Loaders
- There are three types of class loaders:
- Bootstrap Class Loader: Loads core Java API classes from the bootstrap class path.
- Extension Class Loader: Loads classes from the
lib/extdirectory within JDK.
- Application Class Loader: Loads classes from application-level class paths defined in environment variables.
Class Loader Priority
- The bootstrap class loader has the highest priority; if it fails to load a class, control passes to the extension class loader, followed by the application class loader.
Bytecode Verification and Preparation
- After loading classes, bytecode verification occurs to ensure that generated bytecode is valid and secure. If verification fails, an error is raised.
- Memory allocation for static variables happens during preparation with default values assigned until initialization occurs.
Memory Areas in JVM
- The JVM consists of five memory areas:
- Method Area: Contains class-level data including static variables.
- Heap Area: Stores object data and instance variables.
- Stack Area: Each thread has its own runtime stack where local variables are stored as stack frames.
Stack Frame Structure
- Each stack frame contains:
- Local variable table related to method parameters,
- Operand stack used during method execution,
- Reference to the runtime constant pool associated with that method.
Understanding JVM Architecture
Memory Areas in JVM
- The local variable G and the operand stack are essential for intermediate operations, with the runtime workspace acting as an operational inter-stack accumulator (ACC).
- Each thread in the JVM has its own runtime stack; thus, if 10 threads are executing, there will be 10 stacks. However, there is only one heap area shared among all threads.
- The heap and method areas serve as shared memory for multiple threads, making them not thread-safe since data can be accessed by any thread.
- Data stored in stack memory is thread-safe because it is accessible only to the specific thread that owns it.
- Each thread also has a Program Counter (PC) register to hold the address of the next instruction to execute.
Execution Engine Components
- The execution engine consists of several parts: an interpreter and a Just-In-Time (JIT) compiler. The interpreter executes Java programs line by line.
- JIT compiler optimizes performance by compiling frequently called methods into machine code after their first interpretation.
- A profiler identifies "hotspot" methods that benefit from JIT compilation based on their usage frequency.
- Native method information is provided through Java Native Interface (JNI), which allows interaction with native applications and libraries.
Class File Structure Overview
- The class file structure contains critical components such as magic number, minor version, major version, constant pool count, and flags indicating various attributes of the class.
- Important elements include fully qualified names of both current and superclass, interfaces implemented by the current class, fields present in the class, methods defined within it, and additional attributes associated with those methods.
- This comprehensive information about each class file is stored in the method area of JVM for efficient access during program execution.
Understanding the Magic Number in Java Class Files
Overview of Class File Structure
- The class file structure includes various interfaces and fields, such as array interface count and methods count.
Importance of the Magic Number
- The magic number is crucial for the JVM to verify if a class file is valid and generated by a proper compiler. It consists of specific bytes that identify the file format.
Definition and Significance
- The first four bytes of every class file should be
0xCAFEBABE, which is recognized as the magic number. This hexadecimal value indicates a valid class file.
JVM Verification Process
- If the JVM cannot identify these bytes as
0xCAFEBABE, it throws a runtime exception indicating a "class format error," signaling an invalid class file.
Practical Example Demonstration
- A simple Java program demonstrates how to compile code into a class file, which will contain the magic number. The output confirms successful execution when the magic number is present.
Consequences of Altering Class Files
Impact on Execution
- Removing or altering parts of the class file leads to an invalid format, resulting in exceptions during execution due to incompatible magic values.
Exception Handling
- An example shows that if there’s an incompatible magic value, it results in a
java.lang.ClassFormatError, highlighting issues with identifying valid files.
Key Takeaways about Magic Numbers
Summary Points
- The first four bytes (magic number) are essential for JVM validation.
- This predefined value (
0xCAFEBABE) helps determine if a class file was generated correctly.
Runtime Exceptions Explained
- If no valid magic number is found during execution, it triggers runtime exceptions like
java.lang.ClassFormatError.
This structured overview captures critical insights from the transcript regarding Java's handling of class files and their validation through magic numbers.
Understanding Java Compiler and JVM Version Compatibility
Major and Minor Versions in Java
- The discussion begins with the importance of understanding minor and major versions in Java, particularly how they relate to the compiler and JVM (Java Virtual Machine).
- A Java program compiled with a 1.6 version compiler can run on a 1.7 version JVM without issues, as higher version JVMs support lower version class files.
- Conversely, if a class file is generated by a 1.7 version compiler but executed on a 1.6 version JVM, it will result in an "unsupported class file version" exception.
Class File Identification
- The JVM identifies which compiler generated the class file using the minor and major versions embedded within the .class files.
- Each .class file contains these versions that help determine compatibility; for example, a class file from a 1.5 compiler has a major version of 49.
Major Version Values
- The major and minor versions are crucial: for instance, if it's a 1.5 version, its major value is noted as 49.0; for 1.6 it’s 50.0, and for 1.7 it’s 51.0.
- This system allows the JVM to ascertain which specific compiler was used to generate any given class file based on these values.
Practical Demonstration of Compiler Versions
- An example is provided where both the compiler (Java C) and JVM are set to the same version (1.7), ensuring no compatibility issues arise during execution.
- A scenario is presented where two command prompts are opened: one configured for JDK 1.6 (blue text), while another uses JDK 1.7 (red text).
Testing Compatibility Between Different Versions
- The speaker compiles code using both compilers to demonstrate their interaction with different JVM versions—successfully running code compiled with JDK 1.6 on JDK 1.7 but failing when attempting to run code compiled with JDK 1.7 on JDK 1.6.
- An error occurs when trying to execute a class file generated by a higher-version compiler (JDK 1.7) on an older-version JVM (JVM of type JDK 1.6), highlighting how critical understanding these versions is.
Conclusion on Versioning System
- The session concludes by reiterating that major and minor versions represent the .class file's compatibility status, allowing the JVM to identify which compiler produced it effectively.
- Emphasis is placed on how this identification process aids developers in managing their Java applications across different environments efficiently.
This structured overview captures key insights from the transcript regarding Java's compilation process and runtime environment management through its versioning system, providing clarity around potential pitfalls related to mismatched versions between compilers and virtual machines.
Compiler Versioning and Class Files
Understanding Compiler Versions
- The major version of a compiler is indicated by an uppercase 'M', while the minor version is denoted by a lowercase 'm'.
- For example, Java 1.5 corresponds to version 49.0, Java 1.6 to version 50.0, and Java 1.7 to version 51.0.
Compatibility of Class Files
- Class files generated by lower versions of the compiler can be executed on higher versions of the JVM (Java Virtual Machine).
- Conversely, class files produced by higher versions cannot run on lower versions of the JVM, leading to compatibility issues.
Runtime Exceptions
- Attempting to run a class file from a higher version on a lower JVM results in a runtime exception known as "unsupported class version error".
- This error occurs when there is an attempt to execute code compiled with a newer Java compiler on an older JVM.
Class File Structure
Magic Number and Version Information
- The magic number in class files indicates the file format; it helps identify if the file is valid.
Constant Pool Count
- The constant pool count represents the number of constants present in the constant pool within a class file.
- It provides information about various constants utilized throughout the class.
Access Flags
- Access flags indicate modifiers declared for classes, such as public or private visibility.
Class Hierarchy and Interfaces
Fully Qualified Names
- The
thisunderscore field represents the fully qualified name of the current class.
- Similarly, it also denotes the fully qualified name of its immediate superclass.
Interface Implementation
- The interface count reflects how many interfaces are implemented by the current class.
- An array containing information about these interfaces is also provided for further reference.
Fields and Methods Overview
Fields Count
- Fields represent static variables within a class; their count indicates how many fields are present in that specific class.
Methods Count
- The methods count shows how many methods exist within the current class along with details about each method's functionality.
Understanding Class Attributes and Methods in Java
Overview of Class Methods
- The current class provides information about all methods present within it, detailing their functionalities.
- It also offers insights into the attributes count, specifically returning the number of attributes available in the current class.
Insights on Class Attributes
- The discussion emphasizes that the class provides comprehensive information regarding all attributes defined within it, enhancing understanding of its structure.
Profiling Java Classes
- A practical example is given using a Java class file (test.class), demonstrating how to profile this file for deeper insights.
- Key profiling details include last modified date, size (433 bytes), checksums, and versioning information (minor version Z and major version 51).
Understanding Versioning and Constants
- The transcript explains what minor and major versions signify in Java, particularly highlighting that major version 51 corresponds to Java 1.7.
- It also touches upon the constant pool's contents, which includes various constants like
java.lang.Objectandjava.lang.System.out, providing context for their usage in programming.