Ad Code

Responsive Advertisement

Quick Suggests :-

6/recent/ticker-posts

JVM(Java Virtual Machine).

 

JVM(Java Virtual Machine).


What is JVM?

Introducing the Java Virtual Machine.

  1. A specification where working of Java Virtual Machine is specified. But implementation provider is independent to choose the algorithm. Its implementation has been provided by Oracle and other companies.
  2. An implementation Its implementation is known as JRE (Java Runtime Environment).
  3. Runtime Instance Whenever you write java command on the command prompt to run the java class, an instance of JVM is created.

What the JVM is used for.

Figure 1 : High-level view of the JVM
  • Technical definition: The JVM is the specification for a software program that executes code and provides the runtime environment for that code.
  • Everyday definition: The JVM is how we run our Java programs. We configure the JVM’s settings and then rely on it to manage program resources during execution.

What it does?

  • Loads code
  • Verifies code
  • Executes code
  • Provides runtime environment
  • Memory area
  • Class file format
  • Register set
  • Garbage-collected heap
  • Fatal error reporting etc.

Who develops and and maintains the JVM?

Memory management in the JVM.

Garbage collection,

What does ‘close to the metal’ mean?

The JVM in three parts.

1. The JVM specification.

The JVM as a virtual machine,

2. JVM implementations.

3. A JVM instance.

What is a software specification?

Loading and executing class files in the JVM,

JVM Architecture.

Figure 2 : JVM Architecture.

The Java class loader in the JVM,

1) Classloader.

  1. 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.
  2. 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.
  3. 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.

//Let’s see an example to print the classloader name

public class ClassLoaderExample{

public static void main(String[] args){

// Let’s print the classloader name of current class.

//Application/System classloader will load this class

Class c=ClassLoaderExample.class;

System.out.println(c.getClassLoader());

//If we print the classloader name of String, it will print null because it is an

//in-built class which is found in rt.jar, so it is loaded by Bootstrap classloader

System.out.println(String.class.getClassLoader());}}

sun.misc.Launcher$AppClassLoader@4e0e2f2a
null

2) Class(Method) Area.

3) Heap.

4) Stack.

5) Program Counter Register.

6) Native Method Stack.

The execution engine in the JVM,

How the execution engine manages system resources,

7) Execution Engine.

  1. A virtual processor
  2. Interpreter: Read bytecode stream then execute the instructions.
  3. Just-In-Time(JIT) compiler: It is used to improve the performance. JIT compiles parts of the byte code that have similar functionality at the same time, and hence reduces the amount of time needed for compilation. Here, the term “compiler” refers to a translator from the instruction set of a Java virtual machine (JVM) to the instruction set of a specific CPU.

8) Java Native Interface.

JVM evolution: Past, present, future.

The lean, mean, virtual machine.

What is the Java Virtual Machine? Why is it here?

Java bytecodes

Virtual parts

The proud, the few, the registers

The method area and the program counter

The Java stack and related registers

The garbage-collected heap

Eternal math: a JVM simulation

class Act {
public static void doMathForever() {
int i = 0;
while (true) {
i += 1;
i *= 2;
}
}
}

Thread behavior in the JVM.

Find your first thread: Java’s main() method,

public class MainThread {    public static void main(String... mainThread) {
System.out.println(Thread.currentThread().getName());
}
}

The Java thread lifecycle,

  • New: A new Thread() has been instantiated.
  • Runnable: The Thread's start() method has been invoked.
  • Running: The start() method has been invoked and the thread is running.
  • Suspended: The thread is temporarily suspended, and can be resumed by another thread.
  • Blocked: The thread is waiting for an opportunity to run. This happens when one thread has already invoked the synchronized() method and the next thread must wait until it's finished.
  • Terminated: The thread’s execution is complete.
Figure 3 :The six states of the Java threads lifecycle

Concurrent processing: Extending a Thread class,

public class InheritingThread extends Thread {    InheritingThread(String threadName) {
super(threadName);
}
public static void main(String... inheriting) {
System.out.println(Thread.currentThread().getName() + " is running");
new InheritingThread("inheritingThread").start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running");
}
}
main is running.
inheritingThread is running.

The Runnable interface,

public class RunnableThread implements Runnable {    public static void main(String... runnableThread) {
System.out.println(Thread.currentThread().getName());
new Thread(new RunnableThread()).start();
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}

Non-daemon vs daemon threads,

  • Non-daemon threads are executed until the end. The main thread is a good example of a non-daemon thread. Code in main() will be always be executed until the end, unless a System.exit() forces the program to complete.
  • daemon thread is the opposite, basically a process that is not required to be executed until the end.
import java.util.stream.IntStream;public class NonDaemonAndDaemonThread {    public static void main(String... nonDaemonAndDaemon) throws                        InterruptedException {
System.out.println("Starting the execution in the Thread " + Thread.currentThread().getName());
Thread daemonThread = new Thread(() -> IntStream.rangeClosed(1, 100000)
.forEach(System.out::println));
daemonThread.setDaemon(true);
daemonThread.start();
Thread.sleep(10); System.out.println("End of the execution in the Thread " +
Thread.currentThread().getName());
}
}
  1. Start of execution in the main thread.
  2. Print numbers from 1 to possibly 100,000.
  3. End of execution in the main thread, very likely before iteration to 100,000 completes.

Thread priority and the JVM,

/**
* The minimum priority that a thread can have.
*/

public static final int MIN_PRIORITY = 1;
/**
* The default priority that is assigned to a thread.
*/

public static final int NORM_PRIORITY = 5;
/**
* The maximum priority that a thread can have.
*/

public static final int MAX_PRIORITY = 10;
public class ThreadPriority {    public static void main(String... threadPriority) {
Thread moeThread = new Thread(() -> System.out.println("Moe"));
Thread barneyThread = new Thread(() -> System.out.println("Barney"));
Thread homerThread = new Thread(() -> System.out.println("Homer"));
moeThread.setPriority(Thread.MAX_PRIORITY);
barneyThread.setPriority(Thread.NORM_PRIORITY);
homerThread.setPriority(Thread.MIN_PRIORITY);
homerThread.start();
barneyThread.start();
moeThread.start();
}
}

Constants vs enums,

Common mistakes with Java threads,

  • Invoking the run() method to try to start a new thread.
  • Trying to start a thread twice (this will cause an IllegalThreadStateException).
  • Allowing multiple processes to change the state of an object when it shouldn’t change.
  • Writing program logic that relies on thread priority (you can’t predict it).
  • Relying on the order of thread execution — even if we start a thread first, there is no guarantee it will be executed first.

What to remember about Java threads,

  • Invoke the start() method to start a Thread.
  • It’s possible to extend the Thread class directly in order to use threads.
  • It’s possible to implement a thread action inside a Runnable interface.
  • Thread priority depends on the JVM implementation.
  • Thread behavior will always depend on the JVM implementation.
  • A daemon thread won’t complete if an enclosing non-daemon thread ends first.

Method overloading in the JVM.

What is method overloading?

Listing 1. Three types of method overloading

Number of parameters:
public class Calculator {
void calculate(int number1, int number2) { }
void calculate(int number1, int number2, int number3) { }
}
Type of parameters:
public class Calculator {
void calculate(int number1, int number2) { }
void calculate(double number1, double number2) { }
}
Order of parameters:
public class Calculator {
void calculate(double number1, int number2) { }
void calculate(int number1, double number2) { }
}

Method overloading and primitive types

Table 1. Primitive types in Java

Why should I use method overloading?

What overloading isn’t

public class Calculator {

void calculate(int firstNumber, int secondNumber){}
void calculate(int secondNumber, int thirdNumber){}}
public class Calculator {
double calculate(int number1, int number2){return 0.0;}
long calculate(int number1, int number2){return 0;}
}

Constructor overloading

public class Calculator {
private int number1;
private int number2;
public Calculator(int number1) {this.number1 = number1;}

public Calculator(int number1, int number2) {
this.number1 = number1;
this.number2 = number2;
}
}

How the JVM compiles overloaded methods

  1. Widening
  2. Boxing (autoboxing and unboxing)
  3. Varargs
int primitiveIntNumber = 5;
double primitiveDoubleNumber = primitiveIntNumber ;
Figure 4 : The order of primitive types when widenened
int primitiveIntNumber = 7;
Integer wrapperIntegerNumber = primitiveIntNumber;
Integer wrapperIntegerNumber = Integer.valueOf(primitiveIntNumber);
Integer wrapperIntegerNumber = 7;
int primitiveIntNumber= wrapperIntegerNumber;
int primitiveIntNumber = wrapperIntegerNumber.intValue();
execute(int… numbers){}

What is varargs?

execute(1,3,4,6,7,8,8,6,4,6,88...); // We could continue…

Common mistakes with overloading

Autoboxing with wrappers

int primitiveIntNumber = 7;
Double wrapperNumber = primitiveIntNumber;
Double number = Double.valueOf(primitiveIntNumber);
Double wrapperNumber = (double) primitiveIntNumber;

Hard-coded number types in the JVM

class Calculator {
public static void main(String… args) {
// This method invocation will not compile
// Yes, 1 could be char, short, byte but the JVM creates it as an int
calculate(1);
}
void calculate(short number) {}

}
class Calculator {
public static void main(String… args) {
// This method invocation will not compile
// Yes, 1 could be float but the JVM creates it as double
calculate(1.0);
}
void calculate(float number) {}
}
char anyChar = 127; // Yes, this is strange but it compiles

What to remember about overloading

  • First is widening
  • Second is boxing
  • Third is Varargs

Bytecode basics.

The bytecode format,

// Bytecode stream: 03 3b 84 00 01 1a 05 68 3b a7 ff f9
// Disassembly:
iconst_0 // 03
istore_0 // 3b
iinc 0, 1 // 84 00 01
iload_0 // 1a
iconst_2 // 05
imul // 68
istore_0 // 3b
goto -7 // a7 ff f9

Primitive types

// Bytecode stream: 17 01 00
// Dissassembly:
sipush 256; // 17 01 00

Pushing constants onto the stack

Pushing local variables onto the stack

Popping to local variables

Type conversions

class BadArithmetic {
byte addOneAndOne() {
byte a = 1;
byte b = 1;
byte c = a + b;
return c;
}
}
BadArithmetic.java(7): Incompatible type for declaration. Explicit cast needed to convert int to byte.
byte c = a + b;
^
class GoodArithmetic {
byte addOneAndOne() {
byte a = 1;
byte b = 1;
byte c = (byte) (a + b);
return c;
}
}
iconst_1          // Push int constant 1.
istore_1 // Pop into local variable 1, which is a: byte a = 1;
iconst_1 // Push int constant 1 again.
istore_2 // Pop into local variable 2, which is b: byte b = 1;
iload_1 // Push a (a is already stored as an int in local variable 1).
iload_2 // Push b (b is already stored as an int in local variable 2).
iadd // Perform addition. Top of stack is now (a + b), an int.
int2byte // Convert int result to byte (result still occupies 32 bits).
istore_3 // Pop into local variable 3, which is byte c: byte c = (byte) (a + b);
iload_3 // Push the value of c so it can be returned.
ireturn // Proudly return the result of the addition: return c;

Conversion diversion: a JVM simulation

class Diversion {
static void Convert() {
byte imByte = 0;
int imInt = 125;
while (true) {
++imInt;
imByte = (byte) imInt;
imInt *= -1;
imByte = (byte) imInt;
imInt *= -1;
}
}
}
iconst_0          // Push int constant 0.
istore_0 // Pop to local variable 0, which is imByte: byte imByte = 0;
bipush 125 // Expand byte constant 125 to int and push.
istore_1 // Pop to local variable 1, which is imInt: int imInt = 125;
iinc 1 1 // Increment local variable 1 (imInt) by 1: ++imInt;
iload_1 // Push local variable 1 (imInt).
int2byte // Truncate and sign extend top of stack so it has valid byte value.
istore_0 // Pop to local variable 0 (imByte): imByte = (byte) imInt;
iload_1 // Push local variable 1 (imInt) again.
iconst_m1 // Push integer -1.
imul // Pop top two ints, multiply, push result.
istore_1 // Pop result of multiply to local variable 1 (imInt): imInt *= -1;
iload_1 // Push local variable 1 (imInt).
int2byte // Truncate and sign extend top of stack so it has valid byte value.
istore_0 // Pop to local variable 0 (imByte): imByte = (byte) imInt;
iload_1 // Push local variable 1 (imInt) again.
iconst_m1 // Push integer -1.
imul // Pop top two ints, multiply, push result.
istore_1 // Pop result of multiply to local variable 1 (imInt): imInt *= -1;
goto 5 // Jump back to the iinc instruction: while (true) {}

How the Java virtual machine handles exceptions.

Exceptions

class OverflowException extends Exception {
}
class UnderflowException extends Exception {
}
class DivideByZeroException extends Exception {
}
static int remainder(int dividend, int divisor)
throws DivideByZeroException {
try {
return dividend % divisor;
}
catch (ArithmeticException e) {
throw new DivideByZeroException();
}
}
The main bytecode sequence for remainder:
0 iload_0 // Push local variable 0 (arg passed as divisor)
1 iload_1 // Push local variable 1 (arg passed as dividend)
2 irem // Pop divisor, pop dividend, push remainder
3 ireturn // Return int on top of stack (the remainder)
The bytecode sequence for the catch (ArithmeticException) clause:
4 pop // Pop the reference to the ArithmeticException
// because it isn't used by this catch clause.
5 new #5 <Class DivideByZeroException>
// Create and push reference to new object of class
// DivideByZeroException.
DivideByZeroException
8 dup // Duplicate the reference to the new
// object on the top of the stack because it
// must be both initialized
// and thrown. The initialization will consume
// the copy of the reference created by the dup.
9 invokenonvirtual #9 <Method DivideByZeroException.<init>()V>
// Call the constructor for the DivideByZeroException
// to initialize it. This instruction
// will pop the top reference to the object.
12 athrow // Pop the reference to a Throwable object, in this
// case the DivideByZeroException,
// and throw the exception.
Exception table:
from to target type
0 4 4 <Class java.lang.ArithmeticException>

Play Ball!: a Java virtual machine simulation

class Ball extends Exception {
}
class Pitcher {
private static Ball ball = new Ball();
static void playBall() {
int i = 0;
while (true) {
try {
if (i % 4 == 3) {
throw ball;
}
++i;
}
catch (Ball b) {
i = 0;
}
}
}
}
0 iconst_0             // Push constant 0
1 istore_0 // Pop into local var 0: int i = 0;
// The try block starts here (see exception table, below).
2 iload_0 // Push local var 0
3 iconst_4 // Push constant 4
4 irem // Calc remainder of top two operands
5 iconst_3 // Push constant 3
6 if_icmpne 13 // Jump if remainder not equal to 3: if (i % 4 == 3) {
// Push the static field at constant pool location #5,
// which is the Ball exception itching to be thrown
9 getstatic #5 <Field Pitcher.ball LBall;>
12 athrow // Heave it home: throw ball;
13 iinc 0 1 // Increment the int at local var 0 by 1: ++i;
// The try block ends here (see exception table, below).
16 goto 2 // jump always back to 2: while (true) {}
// The following bytecodes implement the catch clause:
19 pop // Pop the exception reference because it is unused
20 iconst_0 // Push constant 0
21 istore_0 // Pop into local var 0: i = 0;
22 goto 2 // Jump always back to 2: while (true) {}
Exception table:
from to target type
2 16 19 <Class Ball>

Post a Comment

0 Comments