JDK (Java Development Kit) is a Kit that provides the environment to develop and execute(run) the Java program. JDK is a kit(or package) that includes two things
- Development
Tools (to provide an environment to develop your java programs)
- JRE (to execute your java program).
JRE (Java Runtime Environment) is an installation package that provides an environment to only run(not develop) the java program(or application)onto your machine. JRE is only used by those who only want to run Java programs that are end-users of your system.
JVM (Java Virtual
Machine) is a very important part of both JDK and JRE because it is
contained or inbuilt in both. Whatever Java program you run using JRE or JDK
goes into JVM and JVM is responsible for executing the java program line by
line, hence it is also known as an interpreter.
- JVM
is responsible for converting the byte code to machine code.
- JVM takes (.class) files and
executes it by managing the memory
- JVM
loads, verifies and executes the code and provides the runtime environment
- JVM
plays a major role in java memory management
JVM Architecture
1) Classloader
Classloader is a subsystem of JVM which is
used to load class files. Whenever we run the java program, it is loaded first
by the classloader.
The classLoading mechanism consists of
three main steps as follows.
- Loading
- Linking
- Initialization
Loading
Whenever JVM loads a file, it will load
and read,
- Fully
qualified class name
- Variable
information (instance variables)
- Immediate
parent information
- Whether
class or interface or enum
There are three built-in classloaders in
Java.
- Bootstrap
ClassLoader:
This is the first classloader which is the super class of Extension
classloader. It loads the rt.jar file which contains all
class files of Java Standard Edition like java.lang package classes,
java.net package classes, java.util package classes, java.io package
classes, java.sql package classes etc.
- Extension
ClassLoader:
This is the child classloader of Bootstrap and parent classloader of
System classloader. It loades the jar files located inside $JAVA_HOME/jre/lib/ext directory.
- System/Application
ClassLoader:
This is the child classloader of Extension classloader. It loads the
classfiles from classpath. By default, classpath is set to current
directory. You can change the classpath using "-cp" or
"-classpath" switch. It is also known as Application
classloader.
Linking
This is the process of linking the data in
the class file into the memory area. It begins with verification to
ensure this class file and the compiler.
Verification: This phase
checks the structural correctness of the .class file by checking it
against a set of constraints or rules. If verification fails for some reason,
we get a VerifyException.
For example, if the code has been built using
Java 11, but is being run on a system that has Java 8 installed, the
verification phase will fail.
Prepare – For all static
variables memory will be allocated and assigned with default values.
Resolve – All symbolic memory
references are replaced with the original references from Method Area.
Initialization
This is the final phase of ClassLoading;
here, all static variables will be assigned with the original values,
and the static block will be executed
JVM Memory Areas
- Method
area: All the class level data such as the run-time
constant pool, field, and method data, and the code for methods and
constructors, are stored here.
If the memory
available in the method area is not sufficient for the program startup, the JVM
throws an OutOfMemoryError.
For example, assume that you have the following class
definition:
public class Employee {
private String name;
private int age;
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
}
In this code example, the field level data such
as name and age and the constructor details are loaded into
the method area.
The method area is created on the virtual machine
start-up, and there is only one method area per JVM.
- Heap
area: Information
of all objects is stored in the heap area. There is also one Heap Area per
JVM. It is also a shared resource.
For example assume that you are declaring
the following instance:
Employee employee = new Employee();
In this
code example, an instance of Employee is created and loaded into the heap area.
The heap is
created on the virtual machine start-up, and there is only one heap area per
JVM.
- Stack
area: For
every thread, JVM creates one run-time stack which is stored here. After a
thread terminates, its run-time stack will be destroyed by JVM. It is not
a shared resource.
- PC
Registers: The
JVM supports multiple threads at the same time. Each thread has its own PC
Register to hold the address of the currently executing JVM instruction.
Once the instruction is executed, the PC register is updated with the next
instruction.
- Native
method stacks: The
JVM contains stacks that support native methods. These
methods are written in a language other than the Java, such as C and C++.
For every new thread, a separate native method stack is also allocated
Execution Engine
Execution engine executes the “.class” (bytecode).
It reads the byte-code line by line, uses data and information present in
various memory area and executes instructions. It can be classified into three
parts:
- Interpreter: It
interprets the bytecode line by line and then executes. The disadvantage
here is that when one method is called multiple times, every time
interpretation is required.
- Just-In-Time
Compiler(JIT) : It is used to increase the efficiency of
an interpreter. It compiles the entire bytecode and changes it to native
code so whenever the interpreter sees repeated method calls, JIT provides
direct native code for that part so re-interpretation is not required,
thus efficiency is improved.
- Garbage
Collector:
The Garbage Collector (GC) collects and removes unreferenced objects from
the heap area. It is the process of reclaiming the runtime unused memory
automatically by destroying them.’
Garbage
collection makes Java memory efficient because it removes the unreferenced
objects from heap memory and makes free space for new objects. It involves two
phases:
- Mark - in this
step, the GC identifies the unused objects in memory
- Sweep - in this
step, the GC removes the objects identified during the previous phase
Garbage
Collections is done automatically by the JVM at regular intervals and does not
need to be handled separately. It can also be triggered by
calling System.gc(), but the execution is not guaranteed.
The
JVM contains 3 different types of garbage collectors:
- Serial GC - This is
the simplest implementation of GC, and is designed for small applications
running on single-threaded environments. It uses a single thread for
garbage collection. When it runs, it leads to a "stop the world"
event where the entire application is paused. The JVM argument to use
Serial Garbage Collector is -XX:+UseSerialGC
- Parallel GC - This is
the default implementation of GC in the JVM, and is also known as
Throughput Collector. It uses multiple threads for garbage collection, but
still pauses the application when running. The JVM argument to use
Parallel Garbage Collector is -XX:+UseParallelGC.
- Garbage First
(G1) GC - G1GC
was designed for multi-threaded applications that have a large heap size
available (more than 4GB). It partitions the heap into a set of equal size
regions, and uses multiple threads to scan them. G1GC identifies the
regions with the most garbage and performs garbage collection on that
region first. The JVM argument to use G1 Garbage Collector
is -XX:+UseG1GC
Note: There is another type of garbage collector called Concurrent Mark Sweep (CMS) GC. However, it has been deprecated since Java 9 and completely removed in Java 14 in favour of G1GC.
Java
Native Interface (JNI)
At
times, it is necessary to use native (non-Java) code (for example, C/C++). This
can be in cases where we need to interact with hardware, or to overcome the
memory management and performance constraints in Java. Java supports the
execution of native code via the Java Native Interface (JNI).
- ClassNotFoundExcecption - This
occurs when the Class Loader is trying to load classes
using Class.forName(), ClassLoader.loadClass() or ClassLoader.findSystemClass() but
no definition for the class with the specified name is found.
- NoClassDefFoundError - This
occurs when a compiler has successfully compiled the class, but the Class
Loader is not able to locate the class file at the runtime.
- OutOfMemoryError - This
occurs when the JVM cannot allocate an object because it is out of memory,
and no more memory could be made available by the garbage collector.
- StackOverflowError - This
occurs if the JVM runs out of space while creating new stack frames while
processing a thread.