JVM Architecture and Class Loaders Java



Being Java developers, it is our responsibility to understand how the JVM internally processes a Java class file. We will discover how JVM handles a.class file and performs the internal processing to produce the result in this article on "JVM Architecture & Class Loaders Java." Just to be clear, the JVM (Java virtual machine) is in charge of converting the compiled.class file into byte-code. Therefore, "JVM Architecture & Class Loaders Java" is the title of this article. In addition, we will learn in-depth the internal architecture of the Java Virtual Machine in addition to the internal processing of a class file.

JVM contains three primary sections :

1. Class Loaders

2. Memory Area

3. Execution Engine


Class Loaders in Java

The class loaders load the compiled class file. The class loader system contains 3 types of class loaders.

1. Bootstrap class Loader (BCL)

2. Extension class Loader (ECL)

3. Application class Loader (ACL)


Bootstrap class loader

Bootstrap Class Loader is responsible for loading all core Java API classes. These are all classes that exist inside rt.jar which are available in all JVMs by default. Bootstrap class loader loads classes from the bootstrap class path. However, its implementation is in native languages(C, C++) but not in java.

Bootstrap Class-Path is JDK/JRE/lib


Extension class loader

Extension Class Loader is a child class of Bootstrap class loader that is responsible for loading all classes from the extension classpath in java. However, its implementation is in java only. The Extension Class Path is: JDK/JRE/lib/ext


Application class loader

Application Class Loader is a child class of Extension class loader that is responsible for loading classes from the application classpath. Its implementation is also in java. The Application classpath is our environment classpath.


How does a class loader work?

Class loaders follow Delegation Hierarchy Principle. When JVM comes across a particular class, first of all, it checks whether the corresponding .class file is already loaded or not. If it is already loaded in the Method area, then the JVM considers that the class is loaded without fail. But If it is not loaded, JVM requests the class loader sub-system to load that particular class accordingly.


The class loader sub-system handovers the request to the application class loader. Further Application class loader delegates the request to the extension class loader which in turn delegates the request to the bootstrap class loader. Now the Bootstrap Class Loader will search in the bootstrap class path, if it is available then the corresponding .class will be loaded by Bootstrap Class Loader. If it is not available then the Bootstrap Class Loader delegates the request to the extension class loader.

Further, Extension Class Loader will search in the extension classpath. if it is available then it will be loaded otherwise Extension Class Loader delegates the request to Application Class Loader subsequently. Now Application Class Loader will search in the application classpath. If it is available, then it will be loaded otherwise in the end we will get a runtime exception saying NoClassDefFoundError or ClassNotFoundException.


Loader Priority BCL>ECL>ACL


For example, Methods to get class loaders are as below :


String.class.getClassLoader();

Test.class.getClassLoader();

Customer.class.getClassLoader();


CustomizedClassLoader extends java.lang.ClassLoader: while developing a web server/application server we can use it to customize the class loading mechanism.


JVM Memory Area

The division of the total Memory area of JVM is into 5 parts :


1. Method Area :

In the method area, One area will be allocated for each JVM.  It will be created at the JVM startup. Class-level binary information & static variables reside in this area. Also, Constant pools will be saved inside the method area. Further, It can be accessed by multiple threads simultaneously, therefore it is not thread-safe.


2. Heap Area :

One area will be allocated for each JVM. It will be created at the JVM startup. Objects reside in this area. It can be accessed by multiple threads simultaneously, therefore it is also not thread-safe.


How can we find the allocated heap area?

Runtime r = Runtime.getRuntime();     

r.maxMemory(); r.initialMemory(); r.freeMemory();  

Runtime is inside java.lang package is a Singleton class.

How to set maximum & minimum heap sizes?

1.  By using command prompt execution of the program :


java -Xmx512m JavaProgramFileName enter

java -Xms64m JavaProgramFileName enter

Where Xmx indicates Maximum Memory & Xms indicates Minimum Memory. Heap memory is finite memory but based on our requirement we can set max & min heap sizes.


2. By Setting ‘JAVA_OPTS’ as a system variable


JAVA_OPTS=”-Xms256m -Xmx512m”

After that in a command prompt run the following command:

SET JAVA_OPTS=”-Xms256m -Xmx512m”

This setting indicates

allocating minimum 256MBs of the heap

allocating maximum 512MBs of the heap


3. Stack Area :

It is available per thread unlike Method & Heap area as they are one per JVM. Each entry in the stack is called a Stack frame or activation record. Also, it is thread-safe as it allocates one memory for each thread. Furthermore, Each stack frame has three parts: local variable array, operand stack, and frame data.

Local Variable Array: It contains values of local variables & method parameters.

Operand Stack: JVM uses it as a workspace, some instructions push the values to it & some pop from it & some others perform arithmetic operations.

Frame Data: It contains all symbolic references related to the method. It also contains references to exceptions related to the method.


4. PC Registers :

(Program Counter Registers) : Internally used by JVM. For every thread, JVM creates a separate PC register. In brief PC register contains the address of currently executing threads.


5. Native Method Stacks :

For every thread, JVM creates a separate native method stack if its native method call.


Note: Method Area, Heap Area, and Stack Area are also considered important memory areas from a programmer's point of view. Method Area, and Heap area are for per JVM whereas the Stack area, PC register & the native method stack are for per thread.


♦ Static Variables are stored in the Method area

♦ Instance Variables are stored in the Heap area

♦ Local Variables are stored in the Stack area

Execution Engine

It is a central component of JVM and is responsible for executing  .class files. It  mainly contains two parts: Interpreter & JIT compiler


Interpreter :

An interpreter reads & interprets bytecode, and converts it into machine code/native code line by line. Because the line-by-line performance of the system goes down. Then JIT compiler comes into the picture in JDK 1.1 version.


JIT Compiler :

The primary purpose of the JIT compiler is to improve performance. In fact, Internally it maintains a separate count for every method. Whenever JVM comes across any method call, first that method is interpreted normally by the interpreter, and the JIT compiler increments the corresponding count variable accordingly.


This process continues for every method. Once any method count reaches a threshold value then the JIT compiler identifies that the method is repeatedly used method. We also call that method a hotspot for the JIT compiler. Then JIT Compiler compiles that method immediately & generates corresponding native code. Next time JVM comes across that method call, then JVM uses native code directly & executes it instead of interpreting it once again so that performance of the system will be improved. However, the threshold count varies from JVM to JVM.


♦ Some advanced JIT compilers recompile generated native code if the count reached the threshold value a second time so that more optimized machine code can be generated. Internally profiler (which is part of the JIT compiler) is responsible to identify hot spots.


****Note : => JVM interprets total program at-least once.

However, JIT compilation is applicable only for repeatedly required methods not for every method.

Additionally, JIT Compiler has an intermediate code generator, code optimizer, target code generator & machine code generator in its whole compilation process.

Execution Engine has a Garbage collector, Security manager, etc.


JNI (Java Native interface) :

JNI acts as a mediator between java method calls & corresponding native libraries. Additionally, JNI is responsible to provide information about native libraries to the JVM.

Native method library: In brief, It just holds native libraries' information.


This is all about “JVM Architecture & Class Loaders Java”. We have discussed each & every section of JVM and the respective section’s role in processing a java class file. Hope that all the points of the title “JVM Architecture & Class Loaders Java” is covered in this article. Moreover, If you want to learn more demanding topics in Core Java kindly visit our Core Java section.


What is the difference between PermGen & Metaspace?

PermGen (JDK 7 & lower versions)

PermGen is a special heap space separated from the main memory heap. Moreover, the full form of the PermGen is the Permanent Generation. JVM uses this space to keep track of metadata such as loaded classes. Additionally, the JVM stores all the static content in this space such as all the static methods, primitive variables, and references to the static objects.


The default maximum memory size for 32-bit JVM is 64 MB and for the 64-bit version, it's 82 MB. However, we can change the default size with the JVM options. When the application tries to load an unusual number of classes, we may see “java.lang.OutOfMemoryError : PermGen space”


Most importantly, Oracle completely removed this memory space in the JDK 8 release.


Metaspace (JDK 8 & higher versions)

Metaspace is a new memory space – starting from the Java 8 version. Specifically, it has completely replaced the older PermGen memory space. The most significant difference is how it handles memory allocation. It is a part of the native memory region. Moreover, Metaspace by default auto increases its size depending on the underlying OS. Here, the garbage collection is automatically triggered when the class metadata usage reaches its maximum metaspace size. Moreover, it does better garbage collection than PermGen. Hence, with this improvement, JVM reduces the chance to get the java.lang.OutOfMemory error.

**************************

********************************

Happy Coding 💓💖✌

Find below some amazing blog posts.

Hashmap implementation in Java 8 and pre-Java 8


Data structures in real-time applications


Why String is immutable in java?


How to connect mobile to android studio without USB?


How to clear cache in SpringBoot java?


How to connect and run localhost api in android studio


How to develop secure android app


Shortest way to swap two number in java


Deadlock in java?

ClassNotFoundException vs NoClassDefFoundError

 When a specific class is not found at runtime, errors such as ClassNotFoundException and NoClassDefFoundError are generated. However, they occur in various different circumstances.


When the Class.forName() or loadClass() methods are used to load a class at runtime and the requested classes are not present in the classpath, a ClassNotFoundException exception is thrown.

An error known as NoClassDefFoundError is produced when a specific class is present at compile time but not at run time.


ClassNotFoundException

ClassNotFoundException is a runtime exception that is thrown when an application tries to load a class at runtime using the Class.forName() or loadClass() or findSystemClass() methods ,and the class with specified name are not found in the classpath. For example, you may have encountered this exception when you try to connect to MySQL or Oracle databases and have not updated the classpath with the required JAR files. Most of the time, this exception occurs when you try to run an application without updating the classpath with the required JAR files.

For example, the below program will throw ClassNotFoundException if the mentioned class “oracle.jdbc.driver.OracleDriver” is not found in the classpath.


If you run the above program without updating the classpath with required JAR files, you will get an exception akin to:



NoClassDefFoundError

NoClassDefFoundError is an error thrown when the Java Runtime System tries to load the definition of a class, and that class definition is no longer available. The required class definition was present at compile time, but it was missing at runtime. For example, compile the program below.


When you compile the above program, two .class files will be generated. One is A.class and another one is B.class. If you remove the A.class file and run the B.class file, Java Runtime System will throw NoClassDefFoundError like below:


Hashmap implementation in Java 8 and pre-Java 8

 What is the difference between hashmap implementation in Java 8 and pre-Java 8?



 The difference comes with the type of storage used for clashing buckets. The HashMap has always worked in a way where the table contains several buckets. 


When a hash is calculated from the key, it then points to which bucket it needs to go to.


However, it is possible that two keys calculate to the same hash or even more likely points to the same bucket. 

This is referred to as a hash clash. And this is why a bucket is used - to hold more than just one item in that spot.


Now, prior to J8, this bucket was just a linked list. I.e. if you did have some clashes in your data, then looking between them was a normal linear search on that bucket. 


What J8 changed was that this became adaptive - e.g. if there’s only a handful of clashing items in a bucket it’s still the same. 

But once there are more than a predetermined amount of clashing items in the same bucket - it is turned into a balanced binary tree instead.


The benefit of this is that if the hashing formula isn’t great and tends to cause many clashes, your average seeks time is still not as bad as an O(N) linear search. 

It’s closer to the O(log N) of a binary search instead.


That’s the major difference since J8. There are also some other ancillary changes affecting this. 

For E.g. the default hash formula on strings was optimized to be both faster and allow for fewer clashes on average. 


Thus if your key is a string (some someone’s name in a contacts list), 

it should calculate that hash faster than before and the likelihood that it would calculate a hash pointing to the same bucket is less.


***********************************************
Happy Coding 💓✌