Tuesday, June 7, 2022

JIT Details

Every programming language uses a compiler to convert the high-level language code into machine level binary code, because the system understands only the binary code. Based on the type of the programming language, compiler differs. Now talking about the Java Programming language, it uses this amazing compiler called the JIT (Just-in-Time) in Java. This blog will tell you all about JIT Java Compiler

Below are the topics covered in this article:

  • What is JIT compiler?
  • How JIT compiler works
  • Advantages of Just-In-Time (JIT) compiler
  • Disadvantages of Just-In-Time (JIT) compiler

What is JIT compiler?

The Just-In-Time (JIT) compiler is a component of the Java™ Runtime Environment that improves the performance of Java applications at run time.

Java programs consists of classes, which contain platform-neutral bytecodes that can be interpreted by a JVM on many different computer architectures. At run time, the JVM loads the class files, determines the semantics of each individual bytecode, and performs the appropriate computation. The additional processor and memory usage during interpretation means that a Java application performs more slowly than a native application. The JIT compiler helps improve the performance of Java programs by compiling bytecodes into native machine code at run time.

The JIT compiler is enabled by default, and is activated when a Java method is called. The JIT compiler compiles the bytecodes of that method into native machine code, compiling it "just in time" to run. When a method has been compiled, the JVM calls the compiled code of that method directly instead of interpreting it. Theoretically, if compilation did not require processor time and memory usage, compiling every method could allow the speed of the Java program to approach that of a native application.

JIT compilation does require processor time and memory usage. When the JVM first starts up, thousands of methods are called. Compiling all of these methods can significantly affect startup time, even if the program eventually achieves very good peak performance.

In practice, methods are not compiled the first time they are called. For each method, the JVM maintains a call count, which is incremented every time the method is called. The JVM interprets a method until its call count exceeds a JIT compilation threshold. Therefore, often-used methods are compiled soon after the JVM has started, and less-used methods are compiled much later, or not at all. The JIT compilation threshold helps the JVM start quickly and still have improved performance. The threshold has been carefully selected to obtain an optimal balance between startup times and long term performance.

After a method is compiled, its call count is reset to zero and subsequent calls to the method continue to increment its count. When the call count of a method reaches a JIT recompilation threshold, the JIT compiler compiles it a second time, applying a larger selection of optimizations than on the previous compilation. This process is repeated until the maximum optimization level is reached. The busiest methods of a Java program are always optimized most aggressively, maximizing the performance benefits of using the JIT compiler. The JIT compiler can also measure operational data at run time, and use that data to improve the quality of further recompilations.

The JIT compiler can be disabled, in which case the entire Java program will be interpreted. Disabling the JIT compiler is not recommended except to diagnose or work around JIT compilation problems.


How JIT compiler works

The Just-In-Time (JIT) compiler is a component of the Java Runtime Environment that improves the performance of Java applications at run time. Java programs consists of classes, which contain platform neutral bytecode that can be interpreted by a JVM on many different computer architectures. At run time, the JVM loads the class files, determines the semantics of each individual bytecode, and performs the appropriate computation. The additional processor and memory usage during interpretation means that a Java application performs more slowly than a native application. The JIT compiler helps improve the performance of Java programs by compiling bytecode into native machine code at run time.

JIT compiler working

The JIT compiler is enabled by default, and is activated when a Java method is called. The JIT compiler compiles the bytecode of that method into native machine code, compiling it "just in time" to run. When a method has been compiled, the JVM calls the compiled code of that method directly instead of interpreting it. Theoretically, if compilation did not require processor time and memory usage, compiling every method could allow the speed of the Java program to approach that of a native application.
JIT compilation does require processor time and memory usage. When the JVM first starts up, thousands of methods are called. Compiling all of these methods can significantly affect startup time, even if the program eventually achieves very good peak performance.


Advantages of Just-In-Time (JIT) compiler

Advantages of JIT compilation include:

  • JIT compilers need less memory usage.
  • JIT compilers run after a program starts.
  • Code optimization can be done while the code is running.
  • Any page faults can be reduced.
  • Code that is used together will be localized on the same page.
  • Can utilize different levels of optimization.


Disadvantages of Just-In-Time (JIT) compiler

Disadvantages of JIT compilation include:

  • Startup time can take a noticeable amount of time.
  • Heavy usage of cache memory.
  • Increases the level of complexity in a Java program.

Monday, June 6, 2022

JVM Details

Whether you have used Java to develop programs or not, you might have heard about the Java Virtual Machine (JVM) at some point or another.

JVM is the core of the Java ecosystem, and makes it possible for Java-based software programs to follow the "write once, run anywhere" approach. You can write Java code on one machine, and run it on any other machine using the JVM.

JVM was initially designed to support only Java. However, over the time, many other languages such as Scala, Kotlin and Groovy were adopted on the Java platform. All of these languages are collectively known as JVM languages.

In this article, we will learn more about the JVM, how it works, and the various components that it is made of.


What is a Virtual Machine?




Before we jump into the JVM, let's revisit the concept of a Virtual Machine (VM).

A virtual machine is a virtual representation of a physical computer. We can call the virtual machine the guest machine, and the physical computer it runs on is the host machine.

A single physical machine can run multiple virtual machines, each with their own operating system and applications. These virtual machines are isolated from each other.

What is the Java Virtual Machine?


In programming languages like C and C++, the code is first compiled into platform-specific machine code. These languages are called compiled languages.

On the other hand, in languages like JavaScript and Python, the computer executes the instructions directly without having to compile them. These languages are called interpreted languages.

Java uses a combination of both techniques. Java code is first compiled into byte code to generate a class file. This class file is then interpreted by the Java Virtual Machine for the underlying platform. The same class file can be executed on any version of JVM running on any platform and operating system.

Similar to virtual machines, the JVM creates an isolated space on a host machine. This space can be used to execute Java programs irrespective of the platform or operating system of the machine.

Java Virtual Machine Architecture


The JVM consists of three distinct components:

  1. Class Loader
  2. Runtime Memory/Data Area
  3. Execution Engine

Class Loader


When you compile a .java source file, it is converted into byte code as a .class file. When you try to use this class in your program, the class loader loads it into the main memory.

The first class to be loaded into memory is usually the class that contains the main() method.

There are three phases in the class loading process: loading, linking, and initialization.

  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.

Runtime Data Area


The JVM spec defines certain run-time data areas that are needed during the execution of the program. Some of them are created while the JVM starts up. Others are local to threads and are created only when a thread is created (and destroyed when the thread is destroyed). These are listed below −

PC (Program Counter) Register

It is local to each thread and contains the address of the JVM instruction that the thread is currently executing.

Stack

It is local to each thread and stores parameters, local variables and return addresses during method calls. A StackOverflow error can occur if a thread demands more stack space than is permitted. If the stack is dynamically expandable, it can still throw OutOfMemoryError.

Heap

It is shared among all the threads and contains objects, classes’ metadata, arrays, etc., that are created during run-time. It is created when the JVM starts and is destroyed when the JVM shuts down. You can control the amount of heap your JVM demands from the OS using certain flags (more on this later). Care has to be taken not to demand too less or too much of the memory, as it has important performance implications. Further, the GC manages this space and continually removes dead objects to free up the space.

Method Area

This run-time area is common to all threads and is created when the JVM starts up. It stores per-class structures such as the constant pool (more on this later), the code for constructors and methods, method data, etc. The JLS does not specify if this area needs to be garbage collected, and hence, implementations of the JVM may choose to ignore GC. Further, this may or may not expand as per the application’s needs. The JLS does not mandate anything with regard to this.

Run-Time Constant Pool

The JVM maintains a per-class/per-type data structure that acts as the symbol table (one of its many roles) while linking the loaded classes.

Native Method Stacks

When a thread invokes a native method, it enters a new world in which the structures and security restrictions of the Java virtual machine no longer hamper its freedom. A native method can likely access the runtime data areas of the virtual machine (it depends upon the native method interface), but can also do anything else it wants.

Garbage Collection

The JVM manages the entire lifecycle of objects in Java. Once an object is created, the developer need not worry about it anymore. In case the object becomes dead (that is, there is no reference to it anymore), it is ejected from the heap by the GC using one of the many algorithms – serial GC, CMS, G1, etc.

During the GC process, objects are moved in memory. Hence, those objects are not usable while the process is going on. The entire application has to be stopped for the duration of the process. Such pauses are called ‘stop-the-world’ pauses and are a huge overhead. GC algorithms aim primarily to reduce this time. We shall discuss this in great detail in the following chapters.

Thanks to the GC, memory leaks are very rare in Java, but they can happen. We will see in the later chapters how to create a memory leak in Java.


Execution Engine


Once the bytecode has been loaded into the main memory, and details are available in the runtime data area, the next step is to run the program. The Execution Engine handles this by executing the code present in each class.

However, before executing the program, the bytecode needs to be converted into machine language instructions. The JVM can use an interpreter or a JIT compiler for the execution engine.

Execution Engine helps in executing the byte code by converting it into machine code and also interact with the memory area. So here are the components involved in executing:

  • Interpreter: It is responsible to read, interpret, and execute java program line by line. So if any method is called multiple times new interpretation required which is the main disadvantage of it.
  • JIT Compiler (Just In Time): The concept of the JIT compiler works only for a repeated method not for every method. To overcome the problem that the interpreter faced while interpreting the byte code, whenever it finds the repeated code, JIT Compiler compiles the entire bytecode and changes it to machine code. This machine code will be used directly for repeated method calls.
  • Intermediate Code Generator
  • Code Optimizer
  • Target Code Generator
  • Profiler

Note: Profiler is there to identify hotspot repeated methods inside JIT.

In order to provide native libraries to the Execution Engine, we have JNI that connects with Native libraries and the Execution Engine.

JNI(Java Native Interface): It acts as a bridge between Execution Engine and Native Method Libraries for providing libraries while executing.

Native Method Libraries: This contains the libraries which are required by the execution engine while executing the byte code.


Preparing Your Development Environment

The Java Development Kit (JDK) is software used for Java programming, along with the Java Virtual Machine (JVM) and the Java Runtime Environment (JRE). The JDK includes the compiler and class libraries, allowing developers to create Java programs executable by the JVM and JRE.

Prerequisites

  • A system running Windows 10.
  • A network connection.
  • Administrator privileges.

Check if Java Is Installed

Before installing the Java Development Kit, check if a Java version is already installed on Windows. Follow the steps below:

  1. Open a command prompt by typing cmd in the search bar and press Enter.
  2. Run the following command:
java -version


The command outputs the Java version on your system. If Java isn't installed, the output is a message stating that Java isn't recognized as an internal or external command.

Download Java for Windows 10

Download the latest Java Development Kit installation file for Windows 10 to have the latest features and bug fixes.

  1. Using your preferred web browser, navigate to the Oracle Java Downloads page.
  2. On the Downloads page, click the x64 Installer download link under the Windows category. At the time of writing this article, Java version 17 is the latest long-term support Java version.


Wait for the download to complete.


Install Java on Windows 10

After downloading the installation file, proceed with installing Java on your Windows system.

Follow the steps below:

Step 1: Run the Downloaded File

Double-click the downloaded file to start the installation.

Step 2: Configure the Installation Wizard

After running the installation file, the installation wizard welcome screen appears.

1. Click Next to proceed to the next step.


2. Choose the destination folder for the Java installation files or stick to the default path. Click Next to proceed.


3. Wait for the wizard to finish the installation process until the Successfully Installed message appears. Click Close to exit the wizard.



Set Environmental Variables in Java

Set Java environment variables to enable program compiling from any directory. To do so, follow the steps below:

Step 1: Add Java to System Variables

1. Open the Start menu and search for environment variables.
2. Select the Edit the system environment variables result.


3. In the System Properties window, under the Advanced tab, click Environment Variables…


4. Under the System variables category, select the Path variable and click Edit:


5. Click the New button and enter the path to the Java bin directory:


Note: The default path is usually C:\Program Files\Java\jdk-17.0.1\bin.

6. Click OK to save the changes and exit the variable editing window.

Step 2: Add JAVA_HOME Variable

Some applications require the JAVA_HOME variable. Follow the steps below to create the variable:

1. In the Environment Variables window, under the System variables category, click the New… button to create a new variable.


2. Name the variable as JAVA_HOME.

3. In the variable value field, paste the path to your Java jdk directory and click OK.


4. Confirm the changes by clicking OK in the Environment Variables and System properties windows.

Test the Java Installation

Run the java -version command in the command prompt to make sure Java installed correctly:


If installed correctly, the command outputs the Java version.

Sunday, June 5, 2022

Features of Java

 

Features of Java

  • Simple and Familiar
  • Compiled and Interpreted
  • Platform Independent
  • Portable
  • Architectural Neutral
  • Object-Oriented
  • Robust
  • Secure
  • Distributed
  • Multi-threaded and Interactive
  • High Performance
  • Dynamic and Extensible

Key Features of the Java Language

The Java language provides certain key features that make it ideal for developing server applications. These features include:

Simplicity

Java is simpler than most other languages that are used to create server applications, because of its consistent enforcement of the object model. The large, standard set of class libraries brings powerful tools to Java developers on all platforms.

The syntax of Java is almost similar to C and C++ so that a programmer is familiar with C/C++ does not have to learn the syntax from scratch. But many features of C/C++, which are either complex or result in ambiguity have been removed in Java.

  1. Java does not support multiple inheritance, as the concept is a bit complex and may result in ambiguity. 
  2. Java does not support global variables, which also lead to many bugs in C/C++ programs. 
  3. Java does not use pointers and does not allow pointer arithmetic, which is cause of most of the bugs in C/C++ programs due to inherent complexity. 
  4. Java does not support operator overloading as it may lead to confusion. 
  5. There is no concept of garbage value in Java. We have to initialize variables before use. 

Portability

Java is portable across platforms. It is possible to write platform-dependent code in Java, and it is also simple to write programs that move seamlessly across systems.

Java programs are platform independent. They follow the policy of write-once-run-anywhere. A Java program written for Windows Platform can run on any other platform (Unix, Linux, Sun Solaris etc.) simply by copying the bytecode (“.class” files). 

There is no need to copy the source code and compile it again as in case of a C/C++ program. This feature has made the Java a powerful language. We can run bytecode on any machine provided that the machine has the JVM. 

JVM is itself is platform dependent but it makes the Java code platform independent. It is actually JVM which converts the bytecode into machine code and executes them

Automatic storage management

A JVM automatically performs all memory allocation and deallocation while the program is running. Java programmers cannot explicitly allocate memory for new objects or free memory for objects that are no longer referenced. Instead, they depend on a JVM to perform these operations. The process of freeing memory is known as garbage collection.

Strong typing
Before you use a field, you must declare the type of the field. Strong typing in Java makes it possible to provide a reasonable and safe solution to interlanguage calls between Java and PL/SQL applications, and to integrate Java and SQL calls within the same application.
No pointers

Although Java is quite similar to C in its syntax, it does not support direct pointers or pointer manipulation. You pass all parameters, except primitive types, by reference and not by value. As a result, the object identity is preserved. Java does not provide low level, direct access to pointers, thereby eliminating any possibility of memory corruption and leaks.

Exception handling

Java exceptions are objects. Java requires developers to declare which exceptions can be thrown by methods in any particular class.
Flexible namespace

Java defines classes and places them within a hierarchical structure that mirrors the domain namespace of the Internet. You can distribute Java applications and avoid name collisions. Java extensions, such as the Java Naming and Directory Interface (JNDI), provide a framework for multiple name services to be federated. The namespace approach of Java is flexible enough for Oracle to incorporate the concept of a schema for resolving class names in full compliance with the JLS.

Security

The design of Java bytecodes and JVM specification allow for built-in mechanisms to verify the security of Java binary code. Oracle Database is installed with an instance of Security Manager that, when combined with Oracle Database security, determines who can call any Java methods.

Standards for connectivity to relational databases

Java Database Connectivity (JDBC) and SQLJ enable Java code to access and manipulate data in relational databases. Oracle provides drivers that allow vendor-independent, portable Java code to access the relational database.

Robust

Most programs fail one of the two reasons: 

1. Memory Management. 

2. Exceptional conditions at run time. 

While designing the language one of the aim was to ensure that Java programs are as robust as possible i.e. they should rarely fail. So due importance was given to the above two factors in the Java. 

In Java memory allocation and de-allocation is handled in the language itself, which eliminates many problems caused due to dynamic memory management features in C/C++. 

Java also supports object oriented exceptional handling features to handle exceptional conditions, which occur at run-time. This allows a Java program to recover and continue execution even after an exceptional condition occurs.

An Introduction to Java and Its History

JavaJava is currently one of the most influential programming languages. It all started in 1990, when an American company that was leading the revolution in the computer industry decided to gather its best engineers together to design and develop a product that would allow them to become an important player in the new emerging Internet world. 

JIT Details

Every programming language uses a compiler to convert the high-level language code into machine level binary code, because the system unders...