Monthly Archives: June, 2015

JVM Architecture at your tips!

Hola people,

Have you ever wondered how are your java files executed or where is your local variables or class data stored or how does JVM works? If yes, and you still confused about all of it, then this post is what you must read.

In this post, we will be discussion JVM Architecture in detail.

INTRODUCTION

Before we start with the JVM architecture, let us revise the compiling and linking of our C code. Lets just brief ourselves to how C codes are compiled and executed and then we’ll go through the overview of Java code compilation and then into the main architecture.

C/C++ CODE

Let us suppose there are 3 classes: a1.c (with main function), a2.c (with f1 function) and a3.c (with f2 function). These classes are then sent to the compiler which then generates machine code for these 3 classes. (a1.obj, a2.obj and a3.obj). The machine code is then sent to the linker to generate an executable code i.e a.exe file. This a.exe file is then sent for execution in RAM. Hence. execution process in C/C++ is quite fast.cprogrambasic001

JAVA CODE

Let us suppose there are 3 java source files: a1.java (with main method), a2.java (with f1 method) and a3.c (with f2 method). These classes are then sent to the compiler which then generates byte code i.e the class files. (a1.class, a2.class and a3.class). The byte code is then sent to the JVM which resides in RAM. (Remember, there is no linking done in Java). The JVM the loads the class files (with the help of class loaders) from respective class paths and then verifies bytecodes for any viruses, etc (Java codes are always secure). The after verifying the byte code, the execution engine executes the byte code and produces machine code. Hence. the process is quite slow compared to C language.

JAVA VIRTUAL MACHINE (JVM)

JVM is a virtual machine that resides in our memory and is responsible to translate bytecode to machine code or into actions or Operating System calls. For example, a request to establish a socket connection to a remote machine will involve an Operating System call. Different Operating Systems handle sockets in different ways – but the programmer doesn’t need to worry about such details. It is the responsibility of the JVM to handle these translations so that the Operating System and the CPU architecture on which the Java software is running is completely irrelevant to the developer. (See figure below.)

java-program-executionBASIC PARTS

JVM consists of 3 components:

1. ClassLoader SubSystem: This system is responsible for loading, linking and initialization of our class files.

  • Loading: Have you ever wondered while using any java class like String, or Object from where do they get imbibed in your project? They must be residing at some place in your system and if they do, they must be loaded before your class_loader_hierarchyapplication does. This loading of all your JAVA API classes path ( the runtime classes in rt.jar, internationalization classes in i18n.jar, and others.)  is done by BOOTSTRAP CLASSLOADER. Then the classes in JAR files in the lib/ext directory of the JRE,etc are loaded by EXTENSION CLASSLOADER. And in the later stage all user-defined classes gets loaded as and when required by SYSTEM CLASS LOADER. So there are basically 3 classloaders: Bootstrap Loader, Extension and System Class Loaders.
  • Linking: The bytecode is verified (all bytecode is verified  for any virus,etc) , prepared (i.e all static variables are initialised to default values) and resolved (all memory symbolic references are replaced with original references from method area) during this process.
  • Initialization: In this phase the static classes are executed and static variables are given their original values.

2. RunTime Memory Areas: As we know, to load any class or to store any variable, constant,etc some memory is required. Also. to execute some memory is again required. This memory is fetched from specially designated Runtime memory areas residing in JVM. JVM consists of 5 runtime data areas.

  • METHOD AREA: It consists of all the class data (static variables, method implementations, etc)
  • HEAP AREA: it consists of the object data.

Both the above areas are not thread-safe i.e all the thread access the same data here. The following are thread-safe areas, i.e one per each thread.fig5-3

  • STACK AREA: For each thread in the stack, a separate memory (TLA) will be allocated. Each entry in the stack is known as a stack frame which consists of 3 parts: local variable, frame data and operands.
  • PC Registers AREA: These hold the next executing instruction for each thread present in stack.
  • NATIVE METHOD STACK AREA: This holds the stack area for native emthods in our code.

3. Execution Engine: This is the central part of the JVM architecture which is responsible to translate your bytecode into machine code i.e your operating system could read and execute. It consists of 4 parts:

  • INTERPRETER: Interpreter does the line by line interpretation of our bytecode.
  • JIT COMPILER: Interpreting the loop code line-by-line can consume a lot of time. The Just-In-Time Compiler comes as a saviour. It compiles the bytecode and generates the machine code at once. It first converts the hotspot code into the intermediate code with the help of intermediate code generator. The Code optimizer then optimizes the intermediate code which is the converted into the native or machine code by target code generator.
  • PROFILER: How do we know, whether the code consists of loops, or recursion is taking place during interpretation of our bytecode? This is done by Profiler. Profiler identifies the hotspots in our bytecode and send them to the JIT compiler.
  • GARBAGE COLLECTOR: It is responsible to remove unused objects present in heap area to allow new object allocations. This process of allocating allocating new objects and removing unused objects to make space for those new object allocations is known as Memory Management. We will discuss it in detail in next post.

jvm-architecture

Sometimes, we require native codes or libraries in our application. These native information is provided by the JNI (Java Native Interfaces) stored in the Native method libraries. The whole JVM Architecture is now explained in the diagram below:

JvmSpec7

SUMMARY

The Java Virtual Machine exists only in the memory of our computer. Reproducing a machine within our computer’s memory requires a mechanism which is the byte code instruction set.

To examine byte code, we can use the Java class file disassembler, javap. By examining bytecode instructions in detail, we gain valuable insight into the inner workings of the Java Virtual Machine and Java itself. Each byte code instruction performs a specific function of extremely limited scope, such as pushing an object onto the stack or popping an object off the stack. Combinations of these basic functions represent the complex high-level tasks defined as statements in the Java programming language. As amazing as it seems, sometimes dozens of byte code instructions are used to carry out the operation specified by a single Java statement. When we use these byte code instructions with the the Virtual Machine, Java gains its platform independence and becomes the most powerful and versatile programming language in the world.

jvm-jre-jdk1

A BEGINNER’S GUIDE TO DEPENDENCY INJECTION!!

Heya people.!

In my last post I discussed about Singletons, its advantages and disadvantages, why it is considered an anti-pattern and stated DI as a better option.In this blog, I will be proving my statement along with going through DI basics and its key benefits.

But, to start with our discussion, we first need to understand the importance of DI.

For example, if we want to make tea for our guests. We will need to collect all the ingredients such as tea leaves, water, kettle , sugar and milk all by ourselves and then put the kettle on the gas to boil water, add tea leaves, milk and sugar and let the mixture boil before we serve it. For all this time, our guests will be waiting for us to get free and meet them. Will it then not be better to have a helping hand who knows better than us to make tea, who will make tea and serve us. If the latter solution excites you, then ladies and gentlemen, welcome to the world of DEPENDENCY INJECTION!

In the above example, if we take tea as an object, then DI help us in initializing the tea object and provide the object with all the necessary resources (i.e in our case ingredients). So basically, DI provides us with what an object needs to get initialized.

Dependency Injection is all about following 3 topics:

  1. Dependency Inversion Principle (DIP)]
  2. Inversion of Control (IOC)
  3. Dependency Injection

DEPENDENCY INVERSION PRINCIPLE

It is a software design pattern that states 2 principles:

  • High-level modules should not depend on low-level modules. They both should depend on abstractions.
  • Abstractions should not depend on details. Instead details should depend on abstractions.

To explain the above principle, let us take a very simple example.

Let us suppose, we have a watcher class that logs a message when it is notified about an event. The class will somewhat look like below:

class EventLog{
    public void log(String msg){
               //log message here
      }
 }

class Watcher{
        EventLog eventLog=null;

        public void notify(String msg){
        if(eventLog==null)
              eventLog=new EventLog();
        eventLog.log(msg);
    }
}

The example given shows no problem at first, but if looked closely violates DI principle. Let us know why!

In the above example, the high level class (Watcher class) depends on the low level class (EventLog class). Also, it depends on the concrete implementation of the low-level class, which completely violates both the principles of DIP.

Also, if at a later stage, requirement arises to extend the functionality of the watcher class i.e probably to send an email or a sms or both, to the designated person every time an event is logged, we’ll have to keep adding concrete implementations in the Watcher class. This will make the code coupled and unmanageable.

class EventLog{
      public void log(String msg){
              //log message here
          }
   }

class Email{

public void email(String msg){
     //email message here
  }
}

class Watcher{

     EventLog eventLog=null;
     Email email=null;

     public void notify(String msg){
     if(eventLog==null)
             eventLog=new EventLog();
      eventLog.log(msg);

     if(email==null)
            email=new Email();
     email.email(msg);
  }
}

Hence to avoid the above situation IOC was introduced.

INVERSION OF CONTROL

It is a mechanism using which we can make the higher level modules depend on abstractions rather than concrete implementations of lower level modules.

Basically we invert the control flow of our code to conform the DIP.

So, for the above example, we make all our concrete classes (EMAIL,SMS and EventLog) implement a common interface or abstract class CommInt consisting of a method actOnNotification().


abstract class CommInt{
       public abstract void actOnNotificstion(String msg);
}

class EventLog extends CommInt{
          public void log(String msg){
              //log message here
        }

     @Override
     public void actOnNotificstion(String msg) {
              log(msg);
     }
}

class Email extends CommInt{
        public void email(String msg){
              //email message here
      }

      @Override
      public void actOnNotificstion(String msg) {
            email(msg);
     }
}

class Watcher{
     CommInt commInt=null;
   
     public void notify(String msg){
       if(commInt==null)
          commInt=new EventLog();

       commInt.actOnNotificstion(msg);

       if(commInt==null)
          commInt=new Email();

        commInt.actOnNotificstion(msg);
    }
}

In the above example, although our concrete classes now depend on abstractions, still to create a concrete type and to assign it to this abstraction we, still have to create the object in our Watcher class, that takes us where we started.

Hence, our third and final topic DEPENDENCY INJECTION comes into play.

DEPENDENCY INJECTION

DI’s main motive is to reduce coupling between classes through injecting concrete implementations of a class that is using abstraction.

There are 3 ways to inject the same:

1. Constructor Injector: We pass the object of concrete class in constructor of dependent class. It is the most widely used.


public class Launcher {

 public static void main(String[] args) {
   Email email=new Email();
   Watcher watcher=new Watcher(email);
   watcher.notify("This Watcher class object sends email for its whole lifetime");

   EventLog eventLog = new EventLog();
   Watcher watcher1 = new Watcher(eventLog);
   watcher1.notify("This Watcher class object logs events for its whole lifetime");

   }
}

abstract class CommInt{
   public abstract void actOnNotificstion(String msg);
}

class EventLog extends CommInt{
   public void log(String msg){
      //log message here
   }

   @Override
   public void actOnNotificstion(String msg) {
     log(msg);
   }
}

class Email extends CommInt{
   public void email(String msg){
     //email message here
   }

   @Override
   public void actOnNotificstion(String msg) {
     email(msg);
   }
}

class Watcher{
   CommInt commInt=null;
   Watcher(CommInt commInt){
     this.commInt=commInt;
   }

   public void notify(String msg){
     commInt.actOnNotificstion(msg);
   }
}

It is useful when we know the instance of the dependent class and will us the same concrete class for its lifetime.

2. Method Injector: We pass object of concrete class into the method of dependent class.


public class Launcher {

  public static void main(String[] args) {
    Email email=new Email();
    Watcher watcher=new Watcher();
    watcher.notify(email,"This Watcher class object first sends email.");
    
EventLog eventLog = new EventLog();
    watcher.notify(eventLog,"and then logs events.!");
  }
}

abstract class CommInt{
  public abstract void actOnNotificstion(String msg);
}

class EventLog extends CommInt{
  public void log(String msg){
    //log message here
  } 

  @Override
  public void actOnNotificstion(String msg) {
    log(msg);
  }
}

class Email extends CommInt{
   public void email(String msg){
     //email message here
   }

    @Override
    public void actOnNotificstion(String msg) {
       email(msg);
    }
}

class Watcher{
      CommInt commInt=null;

      public void notify(CommInt commInt,String msg){
      this.commInt=commInt;
      commInt.actOnNotificstion(msg);
   }
}

It is useful when we need to pass separate concrete class on each invocation.

3. Property Injector: We pass object via a setter property that was exposed by the dependent class. It is used less frequently.


public class Launcher {

    public static void main(String[] args) {
        Email email = new Email();
        Watcher watcher = new Watcher();
        watcher.notify("This Watcher class object first sends email.");

        EventLog eventLog = new EventLog();
        watcher.set(eventLog);
        watcher.notify("and then logs events.!");

    }
}

abstract class CommInt {

    public abstract void actOnNotificstion(String msg);
}

class EventLog extends CommInt {
    public void log(String msg) {
        //log message here
    }

    @Override
    public void actOnNotificstion(String msg) {
        log(msg);
    }
}

class Email extends CommInt {
    public void email(String msg) {
        //email message here
    }

    @Override
    public void actOnNotificstion(String msg) {
        email(msg);
    }
}

class Watcher {

    CommInt commInt = null;

    public CommInt get() {
        return commInt;
    }

    public void set(CommInt commInt) {
        this.commInt = commInt;
    }

    public void notify(String msg) {
        get().actOnNotificstion(msg);
    }
}

It is useful when selection of concrete and invocation of method are in different places.

All the 3 injections are best for one level of dependencies. For a chained or nested dependencies, IOC containers (like Spring, hibernate, etc) come into play. These help us to map the dependencies easily when we have chained or nested dependencies.

KEY BENEFITS

  • maintainable code
  • de-coupled code
  • extendable code
  • move dependency resolution from compile time to run time.
  • centralized configuration
  • improves application testing

In our above example of watcher class,

  • We need to change our launcher to use Email class instead of SMS or EventLog class.
  • Independent unit cases can be created to test all the concrete classes with our Watcher class.

DRAWBACK

The main drawback of dependency injection is that using many instances together can become a very difficult if there are too many instances and many dependencies that need to be resolved.

DI better than Singletons

Singletons maintain a global state which is hard to test. Also, they cannot be extended i.e you can’t change the implementation used by one class without changing it for all of them. For the said reasons, DI will always be a better option! 😀

Hope, the basic concept regarding DI must’ve been cleared. !! For any queries, leave a comment.! 🙂