Skip to content

JVM Architecture

Rohit Agarwal edited this page Jan 21, 2018 · 17 revisions

Virtual Machine

it is a software simulation of a machine which can perform operations like a physical machine. There are two type of virtual machines.

  1. Hardware based or system based - It provides several logical systems on the same computer with strong isolation from each other. That is on one physical machine we are defining multiple logical machines. The main advantage of hardware based virtual machines is hardware resources sharing and improve utilization of hardware resources.
    Example - KVM(Kernal based virtual machine for linux systems), VMWARE, XEN, Cloud computing

  2. Application based or process based - These virtual machines acts as runtime engines to run a particular programming language applications.
    Example -

    • JVM(Java virtual machine) acts as runtime engine to run java based applications.
    • PVM(Parallel virtual machine) acts as runtime engine to run perl based applications.
    • CLR(Common language runtime) acts as runtime engine to run .NET based applications.

Note - JVM is the part of JRE(part of JDK) and it is responsible to load and run java class files.

Basic Architecture diagram of JVM

Class loader subsystem is responsible for the following three activities.

  1. Loading
  2. Linking
  3. Initialization

Loading

Loading means reading class files and store corresponding binary data in method area. For each class file JVM will store corresponding information in the method area.

  • Fully qualified name of class
  • Fully qualified name of immediate parent class
  • Methods information
  • Variables information
  • Constructors information
  • Modifier information
  • Constant pool information etc

After loading .class file immediately JVM creates an object for that loaded class in the heap memory of type java.lang.Class.

The class Class object can be used by programmer to get class level information like methods information, variables information, constructor information etc.

Example

class Student {

	private int name;
	private int rollNumber;

	public int getName() {
		return name;
	}

	public void setName(int name) {
		this.name = name;
	}

	public int getRollNumber() {
		return rollNumber;
	}

	public void setRollNumber(int rollNumber) {
		this.rollNumber = rollNumber;
	}

}

public class Example1 {

	public static void main(String[] args) throws ClassNotFoundException {

		Class c = Student.class;
		Method[] m = c.getDeclaredMethods();
		for (Method m1 : m) {
			System.out.println(m1.getName());
		}
	}

}

For every loaded type only one class object will be created even though we are using the class multiple times in our program.

public class Example2 {

	public static void main(String[] args) {

		Student s1 = new Student();
		Class c1 = s1.getClass();
		Student s2 = new Student();
		Class c2 = s2.getClass();
		System.out.println(c1.hashCode());
		System.out.println(c2.hashCode());
		System.out.println(c1 == c2);// true

	}

}

In the above program even though we are using Student class multiple times only one Class class object got created.

Linking

It is responsible for three activities.

  1. Verify or Verification - It is the process of ensuring that binary representation of a class is structurally correct or not. That is JVM will check whether .class generated by valid compiler or not that is whether.class is properly formatted or not. Internally Bytecode verifier is responsible for this activity. Bytecode verifier is the part of class loader subsystem. If verification fails then we will get runtime exception saying java.lang.VerifyError.
  2. Prepare or Prepration - In this phase JVM will allocate memory for class level static variables and assign default values.
    Note - In the initialization phase original values will be assigned to the static variables and here only default values will be assigned.
  3. Resolve or Resolution - It is the process of replacing symbolic names in our program with original memory refrences from method area.

Example

class Test{
public static void main(String[] args){
String s1=new String("durga");
Student s2=new Student();
}
}

For the above class class loader loads Test.class, String.class, Student.class and Object.class. The name of these classes are stored in constant pool of Test class. In resolution phase these names are replaced with original memory level references from method area.

Initialization

In this phase all static variables are assigned with original values and static blocks will be executed from parent to child and from top to bottom.

Note - While loading, linking and initialization if any error occurs then we will get runtime exception saying java.lang.LinkageError.

Types of Class loaders

  1. Bootstrap class loader or Primordial class loader
  2. Extension class loader
  3. Application class loader or System class loader

Bootstrap class loader or Primordial class loader

it is responsible to load core java Api classes ie the classes present in rt.jar.

This location is called bootstrap classpath ie bootstrap class loader is responsible to load classes from bootstrap classpath (JDK/JRE/lib).
Bootstrap class loader is by default available with every JVM. it is implemented in native languages like C/C++ and not implemented in java.

Extension class loader

It is the child class of bootstrap class loader. It is responsible to load classes from extension classpath (JDK/JRE/lib/ext). Extension class loader is implemented in java and corresponding .class file is sun.misc.Launcher$ExtClassLoader.class.

Application class loader

It is the child class of Extension class loader. This class loader is responsible to load classes from application classpath. It internally uses environment variable classpath. It is implemented in java and the corresponding .class file name is sun.misc.Launher$AppClassLoader.class.

How class loader works?

Class loader follows delegation hierarchy principle. whenever jvm come across a particular class first it will check whether the corresponding .class is already loaded or not. if it is already loaded in method area then jvm will consider that loaded class. If it is not loaded then JVM request class loader subsystem to load that particular class. Then class loaded subsystem handover the request to Application class loader. Application class loader delegates the request to Extension class loader which intern delegates the request to Bootstrap class loader. Then bootstrap class loader will search in bootstrap class path. if it is available then the corresponding .class will be loaded by bootstrap class loader. if is not available then Bootstrap class loader delegates the request to extension class loader. Extension class loader will search in extension classpath. If it is available then it will be loaded otherwise extension class loader delegates the request to Application class loader. Application class loader will search in application class path. If it is available then it will be loaded otherwise we will get runtime exception saying NoClassDefFoundError or ClassNotFoundException.

Example

public class Example3 {

	public static void main(String[] args) throws ClassNotFoundException {

		/*
		 * BootStrap class loader is responsible and we will get null as answer
		 * because it is not written in java.
		 */
		System.out.println(String.class.getClassLoader());
		/*
		 * Application class path is responsible because Example3.class is present
		 * in current working directory
		 * sun.misc.Launcher$AppClassLoader@73d16e93
		 */
		System.out.println(Example3.class.getClassLoader());
		/*
		 * Assume Student class is present in current working directory and
		 * extension class path then Extension class path is responsible and we
		 * will get sun.misc.Launcher$ExtClassLoader@73d16e93
		 */
		System.out.println(Student.class.getClassLoader());

	}
}

Note

  1. BootStrap is not java object hence we got null in the first case but extension and application class loaders are java objects hence we are getting corresponding output for the remaining two SOP's [classname@hashcode_in_hexadecimal]
  2. Class loader subsystem will give the highest priority for bootstrap classpath and then extension class path followed by application classpath.

Need of customized class loader

Default class loaders will load .class file only once even though we are using multiple times that class in our program. after loading .class file if it is modified outside then default class loader won't load updated version of class file(because .class file already available in method area). we can resolve this problem by defining our own customized class loader. The main advantage of customized class loader is we can control class loading machenism based on our requirement. For example - we can load .class file separately every time so that updated version available to our program.

How to define customized class loader?

We can define our own customized class loader by extending java.lang.ClassLoader class.

public class Example4 {

	public static void main(String[] args) throws ClassNotFoundException {

		Test test = new Test();
		MyClassLoader classLoader = new MyClassLoader();// Loaded by default classloader
		classLoader.loadClass("Test");// Loaded by customized classloader
		classLoader.loadClass("Test");// Loaded by customized classloader
	}

}

class MyClassLoader extends ClassLoader {

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.ClassLoader#loadClass(java.lang.String)
	 */
	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException {

		/*
		 * Check for update and load updated .class file and return
		 * corresponding class file.
		 */
		return null;
	}

}

class Test {

}

While developing web servers and application servers usually we can go for customized class loaders to customize class loading mechanism.

What is need of ClassLoader class?

We can use java.lang.ClassLoader class to define our own customized class loaders. Every class loader in java should be child class of java.lang.ClassLoader class either directly or indirectly. Hence this class acts as base class for all customized class loaders.

Various memory area present inside JVM

Whenever JVM loads and runs a java program it needs memory to store several things like Bytecode, objects, variables etc Total JVM memory organized into the following 5 categories.

  1. Method Area
  2. Heap Area
  3. Stack Memory
  4. PC Registers
  5. Native method stacks

Method Area

  1. For every JVM one method area will be available.
  2. Method area will be created at the time of JVM Start up.
  3. Inside Method area class level binary data including static variables will be stored.
  4. Constant pools of a class will be stored inside method area.
  5. Method area can be accessed by multiple threads simultaneously.

Heap Area

  1. For every JVM one heap area is available.
  2. Heap area will be created at the time of jvm start up.
  3. Object and corresponding instance variables will be stored in the heap area.
  4. Every array in java is object only hence arrays also will be stored in the heap area.
  5. Heap area can be accessed by multiple threads and hence the data stored in the heap memory is not thread safe.
  6. Heap area need not be continuous.

Program to display heap memory statistics?

Java application can communicate with JVM by using Runtime object. Runtime class present in java.lang package and it is a singleton class. We can create Runtime object as follows.

Runtime r=Runtime.getRuntime();

Once we got Runtime object we can call the following methods on that object.

  1. maxMemory() - it returns the number of bytes of max memory allocated to the heap.
  2. totalMemory() - it returns number of bytes of total memory allocated to the heap(Initial memory).
  3. freeMemory() - It returns number of bytes of free memory present in the heap.
public class Example5 {

	public static void main(String[] args) {

		double mb = 1024 * 1024;
		Runtime runtime = Runtime.getRuntime();
		System.out.println("Max memory :" + runtime.maxMemory() / mb);
		System.out.println("Total memory: " + runtime.totalMemory() / mb);
		System.out.println("Free memory: " + runtime.freeMemory() / mb);
		System.out.println("Consumed memory: " + (runtime.totalMemory() - runtime.freeMemory()) / mb);
	}

}

How to set max and min heap size?

Heap memory is finite memory but based on our requirement we can set max and min heap sizes ie we can increase and decrease the heap size based on our requirement. we can use the following flags with java command.

-Xmx = To set maximum heap size(max memory)

java - Xmx512M HeapDemo - This command will set max heap size as 512 MB.

-Xms = We can use this command to set minimum heap size(total memory)

java -Xms64M HeapDemo - To set minimum heap size as 64 MB.

Stack Memory

For every thread JVM will create a separate stack at the time of thread creation. Each and every method call performed by that thread will be stored in the stack including local variables also. After completing a method the corresponding entry from the stack will be removed. after completing all method calls the stack will become empty and that empty stack will be destroyed by the JVM just before terminating the thread. Each entry in the stack is called stack frame or activation record.The data stored in the Stack is available only for the corresponding thread and not available to the remaining threads hence this data is thread safe.

Each Stack frame has three parts.

  1. Local Variable Array - It contains all parameters and local variables of the method. Each slot in the array is of 4 bytes. Values of type int, float and reference occupy one entry in the array. Values of double and long occupy two consecutive entries in the array.byte, short and char values will be converted to int type before storing and occupy one slot but the way of storing boolean values is varied from JVM to JVM but most of the JVM follow one slot for boolean values.
  2. Operand Stack - JVM uses operand stack as work space. Some instructions can push the values to the operand stack and some instructions can pop values from operand stack and some instructions can perform required operations.
  3. Frame Data - it contains all symbolic references related to that method it also contains a reference to exception table which provides corresponding catch block information in the case of exceptions.

PC Registers(Program Counter Register)

For every thread a separate PC register will be created at the time of Thread creation. PC registers contains the address of current executing instruction. once instruction execution completes automatically PC register will be incremented to hold address of next instruction.

Native method stacks

For every thread JVM will create a separate native method stack. All native method calls invoked by the thread will be stored in the corresponding native method stack.

Note

  1. Method area, Heap area and Stack area are considered as important memory areas with respect to programmer.
  2. Method area and Heap area are per JVM whereas Stack area, PC register and Native method stack are per thread.
  3. Static variables will be stored in method area, instance variables will be stored in heap area, local variables will be stored in stack area.

Example

class Test {
	Student s1 = new Student();
	static Student s2 = new Student();
	public static void main(String[] args) {
		Test t = new Test();
		Student s3 = new Student();
	}

}

Execution Engine

  1. This is the central component of JVM.

  2. Execution engine is responsible to execute java class files.

  3. It mainly contains two components interpreter and JIT Compiler.

    • Interpreter - It is responsible to read byte code and interpret into machine code(Native code) and execute that machine code line by line. The problem with interpreter is, it interprets every time even same method invokes multiples. Which reduces performance of the system. To overcome this problem sun people introduced JIT compiler in 1.1 version.

    • JIT Compiler - The main purpose of JIT compiler is to improve performance internally JIT compiler maintains a separate count for every method. Whenever JVM come across any method call first that method will be interpreted normally by the interperter and JIT compiler increments the corresponding count variable.

      This process will be continued for every method once if any method count reaches threshold value then JIT compiler identifies that this method is repeatedly used method(Hot Spot). Immediately JIT compiler compiles that method and generates the corresponding native code. Next time JVM come accross that method call then JVM uses native code directly and executes it instead of interpreting once again so that performance of the system will be improved. The threshold count varied from JVM to JVM.

      Some advanced JIT compiler will recompile generated native code if count reaches threshold value second time so that more optimized machine code will be generated. Internally profiler, which is the part of JIT compiler is responisble to identify hot spots.

Note

  1. JVM interprets total program at least once.
  2. JIT compilation is applicable only for repeatedly required methods not for every method.

Java Native Interface (JNI)

JNI acts as mediator for java method calls and corresponding native libraries ie JNI is responsible to provide information about native libraries to the JVM. Native method library provides or holds native libraries information.

Class File Structure

classFile{

magic_number;

minor_version;

major_version;

constant_pool_count;

constant_pool[];

access_flags;

this_class;

super_class;

interface_count;

interface[];

fields_count;

fields[];

methods_count;

methods[];

attributes_count;

attributes[];

}
  1. magic number - The fist four bytes of the class file is magic number. This is a predefined value used by JVM to identify .class file is generated by valid compiler or not. The value should be 0XCAFEBABE.

    Note - whenever we are executing a java class if jvm unable to find valid magic number then we will get runtime exception saying java.lang.ClassFormatError:incompatible magic value

  2. minor_version and major_version - It represents .class file version. JVM will use these versions to identify which version of compiler generates current .class file.



    Note - Lower version compiler generated .class file can be run by higher version JVM but higher version compiler generated .class file can't be run by lower version JVM. If we are trying to run we will get runtime exception saying java.lang.UnsupportedClassVersionError

    Example -

    Javac 1.6 => Java 1.7 (valid)
    javac 1.7 => java 1.6(invalid)

  3. constant_pool_count - It represent number of constant presents in constant pool.

  4. constant_pool[] - It represents information about constant present in constant pool.

  5. access_flags - It provides information about modifiers which are declared to the class.

  6. this_class - It represent fully qualified name of the class.

  7. super_class - It represent fully qualified name of immediate super class of current class.

  8. interface_count - It returns number of interfaces implemented by current class.

  9. interface[] - It returns interfaces information implemented by current class.

  10. fields_count - It represent number of fields(static variable) present in the current class.

  11. fields[] - It represent fields information present in current class.

  12. methods_count - It represent number of methods present in current class.

  13. methods[] - It provides information about all methods present in current class.

  14. attributes_count - It returns number of attributes present in current class.

  15. attributes[] - It provides information about all attributes(instance variables) present in current class.