Let’s learn preface to java virtual machine and architecture.
Every fresher java programmer/developer is aware of Java Virtual Machine which interprets compiled java code known as byte code and excutes it to platform specific machine code.
Java applications are WORA(Write Once Run Anywhere). It is compiled and interpreted. Java compiler complies source code to bytecode.
Then at runtime Java Virtual Machine interprets this bytecode and creates machine code which is executed by machine to run java program.
Preface to java virtual machine and architecture
When we write a java program we use java compiler to compile and get dot class (.class) file or bytecode as an output.
Our application consists of .class (dot class) file which is a sub-output that is generated by the java compiler.
First it is loaded into main subsystems of JVM that is Class Loader Subsystem. The class loader subsystem is responsible for loading java dynamic class.
Class loader subsystem loads, links and initializes class file for the first time at runtime.
Now it should be loaded to perform some operations with respect to other classes which are associated with the JVM.
By using the class loader subsystem the class files are been loaded. There are three sections in class loader subsystem.
Loading is a phase where class files are loaded. Basically loading is of three.
- Bootstrap class loader
- Application class loader and
- Extension class loader.
Above class loaders follow Delegation Hierarchy Algorithm while loading class files.
Bootstrap loader is responsible for loading classes from bootstrap classpath called rt.jar.
You often encounter rt.jar file in java directory which consists of all important classes and packages which are required by java.
Application ClassLoader is responsible for loading Application Classpath level, mentioned Environment Variable path etc.
Extension class loader:
Extension class type loader is responsible for loading important classes which are inside ‘ext’ folder (jre\lib).
Linking is the phase where most of the work is done. Linking involves three sub process which are,
- Preparing and
Verify phase is a phase where java bytecode is taken care of. It basically checks bytecode whether it is compatible to JVM specification or not.
public static boolean bool = false;
In prepare phase variable “bool” which is of boolean type will be initialized to the default value of boolean type which is false not true.
Because prepare phase involves initializing with default value not with original value.
Now resolve phase job is to replace all symbolic memory references with original references.
Runtime Data Area
Runtime data area consists of major components they are,
- Method area
- Heap area
- Stack area
- PC registers
- Native method stacks
Even methods share memory in heap area. Data stored in heap area is not thread safe (because shared resource). Like method area, there is only one heap area in JVM.
Stack area contain stack frame. It is basically per method invocation. Here every thread has a seperate runtime stack. Stack area is not a shared resource hence thread-safe.
Stack memory contains all local variables created. Stack frame is divided into three sub categories,
- Local variable array – local variables and corresponding values are stored
- Operand stack – acts as runtime workspace for in-between operation.
- Frame data – stores symbols relative to method.
PC registers are basically program counter registers which point to next instruction to be executed.
PC register is responsible for per thread management. Suppose there are three threads, one, two and three.
Thread one counts instruction for thread two, thread two counts instruction for thread three. It holds address of current executing instruction and will be updated with next instruction.
Native Method Stack:
Native method stack works parallelly with java stack which holds information related to native method stack. In java, every thread has one seperate native method stack.
Execution Engine is responsible for executing bytecode instruction. It reads bytecode line by line. Execution engine basically comprises of various subsystem namely,
- Garbage collection
- Just-In-Time compiler
Interpreter – interprets bytecode instruction line by line. It checks whether bytecode instructions is compatible to execution engine or not.
Drawback of interpreter is when one program is called several times each time a new definition is needed.
Just-In-Time compiler – Now here comes picture of just-in-time compiler.
Whenever execution engine encounters similar kind of instruction to be executed again and again, what JIT does is it compiles entire bytecode and changes it to native code.
So that it can improve performance in later time. For example, if it encounters XYZ XYZ XYZ multiple times; JIT pre-compiles XYZ automatically.
Now in next instruction if XYZ is encountered, JVM reduces that time, thus leading to performance improvisation.
- Target code generator: generates native code.
- Intermediate code generator: generates intermediate code.
- Code optimizer: optimizes intermediate code.
- Hotspot profiler: detects hotspots meaning to check whether method is called many times or not.
Garbage Collector – garbage collector removes unused objects by calling System.gc() method.
Java Native Interface – this interface communicates with native method libraries and renders it to execution engine.
Native Method Library – combination of native libraries required for execution engine.
This is all about preface to java virtual machine and architecture.