JVM Architecture
JVM Architecture
JVM Architecture
➢ In this chapter, You will learn
o What is VM, JVM, and Types of JVMs, HotSpot technology
o What will happen when we run java command?
o 5 phases in a program development, compilation & execution
o Why Java compiled code is named bytecode?
o .class file structure
o JVM: specification, implementation, and instance
o JVM Architecture Block diagram, JVM Components
o Explanation on Class Loader subsystem (types & algorithm)
o Class Life Cycle: Loading, Linking, Initialization
o Explanation on custom ClassLoader creation
o Explanation on Five Runtime Data Areas
o Explanation on Thread and Stack frame architecture
o Explanation on Method Calls execution flow with PC Register
o Explanation on Java Native Interface (JNI, native method)
o Explanation on Execution Engine (interpreter & JIT Compiler)
o Draw JVM Architecture with programs execution flow
➢ Memory distribution for all 4 types of variables
➢ Methods execution control flow with Stack frames
➢ Program execution with multiple classes with IS-A &
HAS-A relations.
o Changing JVM max & min memory sizes
o Finding JVM Memory Statistics-
▪ Total memory, Free memory, Used memory
o Stand-alone application lifecycle phases & execution flow
o JVM Architecture Final Diagram with complete internal details
➢ By the end of this chapter- you will learn all Components of JVM,
Runtime Data Areas, and their functionalities with complete
execution flow of static and non-static members of a class.
Learn Java with Compiler and JVM Architectures JVM Architecture
JVM Architecture
In this chapter we will learn the internals of JVM, different components of JVM, ClassLoader
subsystem, classes loading mechanism, runtime areas of JVM, execution engine, JNI, different
activities performed inside JVM when class is loaded and object created, memory distribution
for all 4 types of variables, methods execution procedure, etc…
You, being a programmer, no need to learn JVM internals. Instead if you can gain some basic
knowledge on what is happening inside JVM during our class execution then this knowledge
will help you understanding Java program execution easily. This will also help you finding
correct output of an unknown program in interview written test in addition to an
enhancement of skill to develop high performance applications.
If you compare, Knowing about JVM internals is like knowing about Human anatomy in deep
like hands, mouth, throat, stomach, blood and other internal parts which are helping the
digestive system to perform properly to generate energy from the food we eat. Of course, here
we, no need to know about complete functionality of these parts as we are not doctors and
also not going to do any surgery. But by just knowing outer functionality, we can take complete
care in getting energy generated by eating proper food, at proper time in a proper way to live
more years healthy and happy. By knowing body part functionality we can perform first aid to
save life.
So if you compare JVM with your body parts, Food is nothing but the Program you are given to
JVM, then JVM’s internal components are like hand, mouth, throat, stomach will execute
(digest) the given program and gives the output(energy).
As I said in first paragraph, in this chapter we only learn the essential parts of JVM and their
functionality. If you are interested to learn complete details of JVM, you can refer ”JVM
specification given by Oracle (previously Sun)” or refer a text book “Inside the JVM, by Bill
Venners”.
The main reason behind the invention of JVM is to achieve platform independency, means JVM
is invented for running Java compiled code, bytecode, in all available OS irrespective of the OS
in which it is compiled. For this purpose, Oracle Corporation, previously SUN Microsystems,
developed separate JVM for every OS for running Java compiled code by translating it into
current OS specific machine language.
Q2) Well, What is the need of Virtual Machine software, when we can perform operations
directly in computer?
If we perform operations directly in a computer we will have below problems as shown above
1. In one computer we can install only one OS
2. We can run only current OS specific compiled code in a platform dependent way.
3. We cannot use hardware resources effectively
If we perform operations through Virtual machine software will have below benefits
1. In a single computer we can install one OS in another OS
2. We can run any OS compiled program in current OS in a platform independent way
3. We can use hardware resources effectively
Types of JVMs:
The Java 2 SDK, Standard Edition, contains two implementations of the Java virtual machine
• Java HotSpot Client VM
• Java HotSpot Server VM
Java HotSpot Client VM:
The Java HotSpot Client VM is the default virtual machine. By default java program is executed
with client VM. As its name implies, it is tuned for best performance when running applications
in a client environment by reducing application start-up time. The Client version is tuned for
quick loading. It makes use of interpretation.
Java HotSpot Server VM:
The Java HotSpot Server VM is designed for maximum program execution speed for
applications running in a server environment. The Server version loads more slowly, putting
more effort into producing highly optimized JIT compilations, that yield higher performance.
The JVM launcher, java, by default starts client VM, if we want to start the Java HotSpot Server
VM we must use the java command-line option -server when launching an application, as
shown below:
java Test -> class Test is executed by client VM
java -server Test -> class Test is executed by server VM
History of HotSpot
HotSpot is a technology it improves performance of application execution. This technology
provides techniques such as just-in-time compilation and adaptive optimization designed to
improve performance.
The Java HotSpot Performance Engine, first released in April 27, 1999, built on technologies
from the Strongtalk implementation of the Smalltalk programming language originally
developed by Longview Technologies, which traded as "Animorphic". Animorphic's virtual-
machine technology had earlier been successfully used in a Sun research project, the Self
programming language. In 1997 Sun Microsystems purchased Animorphic.
Shortly after acquiring Animorphic, Sun intended to write a new just-in-time (JIT) compiler for
the newly developed virtual machine. This new compiler would give rise to the name
"HotSpot", which derives from the fact that, as the software runs Java bytecode, it continually
analyzes the program's performance for "hot spots" which are frequently or repeatedly
executed. These are then targeted for optimization, leading to high-performance execution
with a minimum of overhead for less performance-critical code. In one report, the JVM beat
some C++ or C code in some benchmarks.
Initially available as an add-on for Java 1.2, HotSpot became the default Sun JVM in Java 1.3.
Thread synchronization:
• The Java programming language allows for use of multiple, concurrent paths of
program execution (called "threads").
• Java HotSpot technology provides a thread-handling capability that is designed to scale
readily for use in large, shared-memory multiprocessor servers.
With the above command, JVM process will be launched by occupying some memory from
RAM, Test class bytecode will be loaded into JVM memory and executed, output is displayed.
Once JVM process is created, JVM will search the given class bytecode in its memory. If the
given class is not loaded into JVM, JVM will request ClassLoader to load the given class
bytecode. Then ClassLoader will load the given class bytecode for the hard disk folder
which is configured in classpath environment variable.
If the given class file is not found, ClassLoader will throw exception
java.lang.ClassNotFoundException/java.lang.NoClassDefFoundError (both are same).
After class loading phase, BytecodeVerifier verifies the loaded bytecode’s internal format.
If the bytecode is in JVM understandable format, it allows interpreter to execute loaded
bytecode. If loaded bytecode is not in the JVM understandable format, it will terminate
execution process by throwing exception "java.lang.ClassFormatError".
After byte code verification completed, interpreter will executed loaded bytecode by
converting them into current OS machine language. While executing bytecode if any logical
mistakes found, JVM will throw associated exception.
Q) What is bytecode?
Java bytecode is the instruction set of the Java virtual machine. It is an intermediate code of all
operating systems. The basic need of bytecode is to achieve platform independency through
JVM. Compiler software will convert Java Source code into bytecode, and then JVM will
convert bytecode into machine language code of current OS in which it is running.
The Java bytecode instruction set is made up of 256 opcodes. As of 2015, 198 are in use, 54 are
reserved for future use, and 3 instructions are set aside as permanently unimplemented.
JVM Components:
As shown in above diagram JVM is a combination of 4 components
1. ClassLoader subsystem
2. Runtime Data Areas
3. Execution Engine
4. Java Native Interface(JNI)
Runtime Data Areas are responsible to provide memory to store byte code, objects,
parameters, local variables, return values and intermediate results of computations.
ClassLoader subsystem is responsible to load and store given class byte code in to JVM from
both the program and the Java API and also it is responsible to link the loaded class to runtime
application of JVM and initialize the loaded class memory.
Execution engine is responsible to execute the loaded byte code with the help of interpreter
and JIT compiler.
Java Native Interface (JNI): It is responsible to link Java method to native method, executes
native method from a Java program and returns its result to Java program.
Below diagram will show you the interaction between ClassLoader, Execution engine, and JNI.
ClassLoader subsystem
ApplicationClassLoader Resolve
In Class Loading phase ClassLoader will load & store given class bytecode into JVM’s Method
Area. ClassLoader subsystem contains three types of class loaders for loading core Java API
classes and userdefined classes. They are
1. BootstrapClassLoader/PrimordialClassLoader
2. ExtensionClassLoader
3. ApplicationClassLoader/SystemClassLoader
BootStrapClassLoader
1) It is responsible to load Java library classes from BootStrapClasspath
i.e.; from jdk\jre\lib\rt.jar file.
2) It is part of the Java Virtual Machine implementation.
3) It is implemented in native API, so it does not have class name.
4) If we try to display its name, null will be displayed.
ExtensionClassLoader
1) It is responsible to load user defined classes or Java library classes from
ExtensionClasspath, i.e.; from jdk\jre\lib\ext folder.
2) It is part of Java API implementation.
3) This class loader is implemented in Java with class name ExtClassLoader.
4) This class is defined as inner class in sun.misc.Launcher class.
5) So, when we try to display its name it is displayed as sun.misc.Launcher$ExtClassLoader.
ApplicationClassLoader
1) It is responsible to load user defined classes from ApplicationClasspath.
2) It will load classes from current working directory or from the folders configured in
classpath environment variable.
3) This class loader is also implemented in Java with class name AppClassLoader.
4) This class is also defined as inner class in sun.misc.Launcher class.
5) So, when we try to display its name it is displayed as sun.misc.Launcher$AppClassLoader.
1) When JVM come across a type, it checks for that class bytecodes in method area. If it is
already loaded, it makes use of the loaded class bytecode type. If the class is not yet
loaded, JVM requests class loader subsystem to load this class.
2) Then ClassLoader subsystem, first handovers this request to ApplicationClassLoader.
3) As per the Parent-delegation principle, the application loader, without searching for
this class in the folders configured in Classpath environment variable, delegates the
request to its parent ClassLoader ExtensionClassLoader.
4) Then ExtensionClassLoader, in turn delegates request to its parent ClassLoader
BootStrapClassLoader.
5) BootStrapClassLoader is the final parent ClassLoader, then it will search the given class
in BootStrapClasspath(jdk\jre\lib\rt.jar and other jar files available in lib folder)
6) If class is found, it will load the class into JVM. If class is not found,
BootStrapClassLoader will send request back to ExtensionClassLoader.
7) Then ExtensionClassLoader will search this class in ExtensionClasspath(jdk\jre\lib\ext
folder jar files).
8) If class is found in ext folder jar files, it will load the class into JVM. If class is not found,
ExtensionClassLoader sends request back to ApplicationClassLoader.
9) Then ApplicationClassLoader will search this class in ApplicationClasspath(classpath
folders).
10) If class is found in application classpath it will load the class into JVM. If here also class
is not found, then we get an exception "java.lang.NoClassDefFoundError" or
"java.lang.ClassNotFoundException".
11) If class is found in any one of the classpaths, the respective ClassLoader will load this
class into JVM's method area by creating java.lang.Class instance.
12) Then JVM will use the loaded bytecodes to complete the execution of this class.
Below diagram will show you the class loader subsystem architecture
5
Searches in BootStrapClasspath
Bootstrap (jdk\jre\lib\rt.jar file)
ClassLoader
6
4
7
Searches in ExtensionClasspath
Extension (jdk\jre\lib\ext folder)
ClassLoader
8
3
or 10
java.lang.ClassNotFoundException
1 10
j.l.C instance
Given
class
Bytecode 11
Stored
Note: AppClassLoader will load class only if class is not found by Bootstap and ExtClassLoader
Q) If the given class is found in Extension directory and alos in local directory, from which
directory this class is loaded and by which class loader?
A) class will be loaded from extension directory by ExtClassLoader
As per parent-delegation algorithm, the extension classpath will be given first priority. Then if
class is given class is found in both extension folder and in current working directory, this class
will loaded from extension folder by ExtClassLoader.
Create and Run below classes to find the class loader through which the given class is loaded
//Example.java //Sample.java
class Example{ package p1;
public class Example{
}
}
//ClassLoaderNamePrinter.java
class ClassLoaderNamePrinter{
public static void main(String[] args) {
System.out.println( java.lang.String.class.getClassLoader());
System.out.println( p1.Sample.class.getClassLoader());
System.out.println( Example.class.getClassLoader());
}
}
Save Example.class in only local folder and Sample.class in both ext folder and local folder,
then Compile and Execute above main method class as shown in below diagram
➔ Loading, linking, and initialization will occur at the beginning of a class’s lifetime
➔ Execution, instantiation (object creation), garbage collection, and finalization will occur in
the middle of a class’s lifetime and
➔ The finalization and unloading of types will occur at the end of a class’s lifetime.
Loading, Linking and initialization
The Class loader subsystem will make types available to the JVM running program through a
process of loading, linking, and initialization. It means, the class loader subsystem is not only
responsible for loading the binary data for classes in to JVM. It must also verify the correctness
of imported classes, allocate and initialize memory for class variables, and assist in the
resolution of symbolic references. All these activities are performed in the order strictly as
shown in the below diagram:
1) Loading is the process of finding the given class, copy its bytecode from .class file and
storing its binary form in JVM’s method area.
2) Linking is the process of incorporating the binary type data into the runtime state of
the virtual machine. Linking is divided into three sub-steps:
▪ Verification, Preparation, and Resolution.
1) In Verification phase ClassLoader will the type is properly formed and fit for use
by the JVM.
2) In Preparation phase static variables memory is allocated with default values
based on their data type.
3) In Resolution phase symbolic references in the constant pool are transferred
into their direct references.
3) In initialization phase static block is executed and the static variables are initialized
with their initial values given in their declaration.
4) In execution phase class execution is stated with main method
5) Once main method execution is completed the class is unloaded from the JVM
Whenever we run java command for executing a class, the Java launcher, java, starts the Java
runtime environment as a process in OS by occupying some memory from RAM, and further
the entire Java Virtual Machine setup is divided into various run-time data areas that are used
during execution of a program. Some of these data areas are created on Java Virtual Machine
start-up and are destroyed only when the Java Virtual Machine exits. Other data areas are
created per thread. Per-thread data areas are created when a thread is created and destroyed
when the thread exits.
JVM totally contains five runtime areas
1. Method Area
2. Heap Area
3. Java Stacks Area
4. Program Counter Registers Area
5. Native Methods Stacks area
About Method Area and Heap Area
1) In Method area every class bytecode is loaded and stored. It means the given class
static and instance variables declaration statements, blocks, methods, and constructors
logic will be stored in method area.
2) Further for all static variables memory is allocated in this runtime area.
3) Heap is the main memory of JVM.
4) All classes and arrays objects are created in heap area. Means given class instance
variables memory is allocated in heap area.
5) For storing given class bytecode inside JVM, one separate instance is created from
java.lang.Class. As many classes are loading into JVM those many instances are created
for java.lang.Class as shown in the below diagram
6) Below diagram will show you classes bytecode storing and object creation in JVM
7) Both Method area and Heap area are sharable memory areas to all threads.
8) Method area and heap area are created on virtual machine start-up.
9) If there is no sufficient memory in method area for loading new class bytecode or there
is not sufficient memory in heap area for creating new object, then JVM will throw
exception java.lang.OutOfMemoryError.
10) The heap memory size can be increased at the time of setting up of runtime
environment using non standard option as show in the below command
java -xms <size> classname
11) The method area and heap area may be of a fixed size or may be expanded as required
by the computation and may be contracted if a larger heap becomes unnecessary.
Learning JVM architecture theory points is not enough. Let try to understand all above points
practically with a program execution with all four types of variable and their memory
distribution done inside runtime data areas:
8. Once main method execution completed, its stack frame is destroyed, main thread is
destroyed and Sample class is unloaded, JVM destroyed.
9. In PC registers area one pc register is created for tracking main thread execution.
10. This complete execution is tracked by execution engine one of the JVM components.
Below diagram will show you java.lang.Class object structure for storing given class bytecode
using above 6 classes.
7) Above diagram shows a snapshot of a virtual machine instance in which three threads
are executing. Threads one and two are executing Java methods. Thread three is
executing a native method. As shown in above diagram, in this book we will draw stack
diagram, the stacks are growing downwards. The "top" of each stack is shown at the
bottom of the figure.
Note: Inside a thread if there is no sufficient memory for creating new stack frame for
execution a method, then JVM will throw exception java.lang.StackOverflowError.
Thread Architecture
1) Thread is an independent sequential flow of execution created in JSA.
2) Every thread is internally divided into multiple sub blocks.
3) This sub block technically called as stack frame.
4) As many methods as we invoke those many stack frames are created in this thread
sequentially.
5) Inside a thread only one stack frame is active at any point. When we invoke a method
from the currently executing method, this current frame is paused, new frame is
created for this invoked method, control is sent to this new frame, this invoked method
logic is loaded into this frame from method area, logic is executed. After this method
execution is completed, its stack frame is destroyed, control return to previous method
stack frame from which this method is invoked.
6) If this method has any parameter and local variables, they are all created inside this
method's stack frame, and are destroyed automatically when Stack Frame is destroyed.
7) Note that a frame created by a thread is local to that thread and cannot be referenced
by any other thread, its means it is not sharable like method area and heap area.
Below diagram will show you main thread with several methods stack frames
▪ All parameters and local variables memory is created in Variables storage area
▪ Method logic is executed in operand stack. To execute method logic, operand stack is
divided into number of blocks. Each block is called slot. This slot size is 32bits (4 bytes - int/
float data type depending of the variable type).
▪ Due to the slot size 4 bytes the result value will be return as 4 bytes value. So due to this
reason in an expression byte, short, char data types are automatically promoted to int data
type. So, the result will coming out from an expression is int type.
▪ The frame data portion will contain data to support constant pool resolution, normal
method return, and exception dispatch information.
Below diagram shows Stack Frame architecture for add method
Some more details of stack frame with “this” and “super” keywords
We will learn in static & Non-static members chapter.
3) To create native method, we must place native keyword in its prototype and it should
not have body. A Java program interacts with the host OS by invoking native methods.
For example
class Example{
public static native int add(int x, int y); It is a native method.
public static void main(String[] args) {
add(10, 20);
}
}
The above program add(int, int) method is a native method. It is compiled fine, but in
execution JVM will throw exception: java.lang.UnsatisfiedLinkError, because we just defined
native method, but we did not defined it required C program and not linked.
Q) If we define a program in C or C++, how can we link this native logic to native method?
A) By using JNI - Java Native Interface. It is a mediator between Java native method and
original native method for linking its method calls.
About Java Native Interface (JNI):
It is one of the JVM components. It is responsible to link Java method to native method,
executes native method from a Java program and returns its result to Java program.
About Execution Engine:
1) It is one of the JVM Components. It is responsible to execute java bytecode.
2) All executions happening in JVM are controlled by Execution Engine.
3) It uses interpreter, JIT compiler, Profiler, SecurityManager for executing a program
4) Execution Engine will also contains Garbage Collector for destroying unreferenced
objects from Heap Area. Below is Execution Engine Block diagram
Execution Engine
If you really want to learn more details about execution flow of your byte code do below
three things
1. After every class you compile, read its byte code using below command
javap –verbose classname
2. Study a Book called Inside the Java Virtual Machine - by Bill Venners