Inside the Java Virtual Machine

The Java Virtual Machine (also known as the JVM), is an engine that provides support for running Java programs. This article talks about the Java Virtual Machine (JVM), and its features and components. We discuss how the class loader, garbage collection, JIT (Just-in-Time), and so forth work.

Components of the Java Virtual Machine (JVM)

The three main subsystems of the JVM include the following:

  • Execution Engine
  • Runtime Data Area
  • Class Loader Subsystem

The Execution Engine

The execution engine is the component that is responsible for executing bytecode inside the context of the Java Virtual Machine. The Execution Engine comprises the following components:

  • Interpreter - The interpreter is responsible for interpreting the byte code at runtime. The primary disadvantage of the interpreter is that it is slow in execution and when you call a method multiple times, interpretation is needed each time.
  • JIT Compiler - The JIT Compiler accepts bytecode as input and converts it into native code. Before converting the bytecode into native machine language, the JIT Compiler performs a number of optimizations.
  • Garbage Collector – The Garbage Collector runs in the background and cleans up memory occupied by objects that are not being referenced or used.

The Runtime Data Area

The Runtime Data Area section comprises the following components:

  • Method Area - The method area stores class level data. The method area contains information related to classes such as class name, parent class name, methods, and information related to static and non-static variables. There is one method area per JVM.
  • Heap Area - The heap area stores object created inside the JVM. It should be noted that there is one heap area per JVM. The heap area is created as soon as JVM starts and it can grow or shrink in size dynamically.
  • Stack Area - Each thread contains a separate runtime stack which in turn is thread safe. Local variables pertaining to a method are created in the stack.
  • Stack Frame – A stack in the JVM is comprised of stack frames (or frames) or activation records. A stack frame contains the state of each method execution in the JVM. At runtime, when a thread calls a method, the JVM adds a new frame to the stack. When the method completes its execution, the JVM pops and discards the method's frame. A stack frame is comprised of the following:
    • Local Variable Array - this contains the method parameters and local variables.
    • Operand Stack - this contains the intermediate result of a calculation
    • Frame Data - this contains all symbolic references as well as references to exception tables
  • PC Registers – A thread has its own PC Register, which is used to store the address of the currently executing instruction. As soon as the execution of an instruction is over, the PC Register is updated accordingly.
  • Native Method Stacks - Typically, you will have one native stack per thread. These stacks are used to save information related to a local method.

The Class Loader SubSystem

The ClassLoader Subsystem is one that loads compiled Java files, (for example: .class files). It is the responsibility of the class loader subsystem to ensure that the class file is properly loaded, linked, and initialized when it is referenced for the first time. The process of loading a class in JVM can further be subdivided into loading, linking, and initialization.

  • Loading - In this phase a class is loaded using the fully qualified name. Note that while the ClassLoader instances and instances of classes are stored in the heap, their class information is located in the method area.
  • Linking - The linking process is further divided into three stages - verification, preparation, and (optionally) resolution. In the verification stage the runtime checks if a type adheres to the Java language semantics and doesn't violate the integrity of the JVM. Memory for the class variables is allocated during the preparation phase. The Java Virtual Machine (JVM) initializes these variables as well during this phase. The resolution process is optional and it loads classes, interfaces and methods that have been referenced symbolically from a type's constant pool.
  • Initialization - This is the final step before your class or interface is ready for the first usage. In this phase the class variables are set to their initial values.

Different types of ClassLoaders in the JVM

The following are the three integrated class loaders in Java Virtual Machine:

  • Bootstrap ClassLoader - This class loader is adept at loading all Java standard Edition class files - the JDK internal classes, notably rt.jar and other essential libraries found in the $JAVA HOME/jre/lib directory, are loaded during this process. It should be noted that the Bootstrap ClassLoader is the parent of all other ClassLoader instances in the Java Virtual Machine.
  • Extension ClassLoader - This class loader is derived from the Bootstrap ClassLoader and is responsible for loading extensions to core Java classes from the proper JDK extension directory.
  • Extension ClassLoader - When the CLASSPATH environment variable is set, this class loader loads all application-specific classes from the location indicated in the environment variable.

How Do Class Loaders Work?

At runtime when the JVM requests a class, the class loader searches the class by taking advantage of the fully qualified name of the class and loads it. Note that the java.lang.ClassLoader.loadClass() method is responsible for loading a class definition into the runtime environment.

If the requested class has not yet been loaded, the request is passed to the parent class loader. What happens if the parent class loader is unable to discover the class? Well, in this case, the child class uses the java.net.URLClassLoader.findClass() method to search for the class in the file system. Now, if the last child class loader fails to load the class either, a java.lang.NoClassDefFoundError or java.lang.ClassNotFoundException is thrown.

Summary of the Java Virtual Machine

The JVM is part of the JRE and calls the main method in your program. The JVM facilitates portability - Java applications support WORA, an acronym for Write Once Run Anywhere.

Article written by: Joydip Kanjilal

Microsoft Most Valuable Professional, Author & Speaker

Winner of Community Credit Awards and MSDN Featured Developer of the Fortnight

Blogs: http://www.infoworld.com/blog/microsoft-coder
Twitter: https://twitter.com/joydipkanjilal
WebSite: joydipkanjilal.net