Getting Acquainted With The JVM (Java Virtual Machine)

The purpose of the JVM is to execute the bytecode that the Java compiler has generated.

As someone who has spent years coding in Java and now Scala, I have come to really appreciate the JVM in all its functionality. There are some great advantages from being able to write code once and run it anywhereβ€” which is something you lack with other virtual machines for languages like Cβ€” to automatically storing and managing memory.

In being the very basis for running many OOP languages, especially the ones mentioned on this site, it is crucial to know about the JVM. And fully understanding those aforementioned advantages will give you a new perspective on objected-oriented programming and why it needs the JVM.

What Is The JVM?
JVM Components
JVM, JDK, JRE

Vocabulary CheckπŸ“–

A thread is the path taken to execute a program from start() to stop().

Allocating is when memory space is added to a storage area.

Contiguous memory allocation refers to a memory management technique in which only one segment of memory is assigned to execute a process.

Native or binary code is code that directly instructs the Central Processing Unit; machine code.

If something is interoperable, it can exchange information.

What is the JVM?

As with any VM (virtual machine), the JVM is the virtual implementation of a computer processor that JVM-supported languages run on.

πŸ€”Whoa! Need Layman's Terms Please!

The JVM behaves like a CPU and processes the byetcode for it's machine.πŸ˜‰

Such languages are:

  • Java
  • Kotlin
  • Scala
  • Groovy

And many more, but these are some of the most popular. All of these languages are interoperable with Java and can use Java's libraries, but everything compiles down to bytecode. The purpose of the JVM is to execute the bytecode that the Java compiler has generated.

JVM Components

Now Let's look at the parts of this machine.

Class Loaders

Class loaders are objects responsible for dynamically loading classes to the Java Virtual Machine, so the JVM itself need not worry about files and file systems when running Java programs. Class loaders are also part of the Java Runtime Environment (JRE) which we will discuss further.

Runtime Data Areas

We are provided multiple areas of memory in which the JVM executes a Java program during runtime known as runtime data areas. For neither of the ones mentioned does the memory need to be contiguous. Let's take a general look at the following:

    Method Area β€” aka, permenant generation space (PermGen). Created on JVM startup. Resembles a storage area for compiled code. Stores runtime constant pool, field and method data, and code for constructors and class names. Is shared by all JVM threads.

    Heap Area β€” allocates memory for instantiated objects. Created on JVM startup. Is shared by all JVM threads.

    Stack Area β€” stores frames of local variables, partial results and nested method calls. Is created whenever a thread is created. Is private for each thread.

And then there are the pre-thread data areas like PC Register, JVM Stack, and Native Method Stack that are created in pair to a new thread and only used by that thread.

Execution Engine

Execution Engine executes the byte code that was assigned to the runtime data areas in JVM via class loader. It is composed of three parts:

    Interpreter β€” executes code in a line-by-line fashion which proves to be a slow run, and it can take even longer if one method is called more than once. But this is not so much a problem thanks to...

    Just-In-Time Compiler (JIT) β€” compiles the frequently called methods at runtime as native code. Distinguishes what methods are eligible for execution, then schedules their compilation in machine code. The methods are now "hot" methods and their compilation into machine code occur on a separate thread so there is no interference with executing the current program. This results in a faster run.

    Garbage Collector (GC) β€” sorts through heap memory for used and unused objects, then deletes the ones no longer in use. This allows for more space in memory. Apparently, GC is considered a "daemon thread" (don't ask me why), but its nature is to continue running even after the JVM has exited the program. GC can be called explicitly using System.gc() method, however, it won't execute immediately. The JVM decides when to invoke GC.

JVM, JDK, JRE

So, what is the JVM versus the JDK versus the JRE? Well, these are in fact three different things that rely on each other for the creation of a complete Java application. We have already defined the JVM as the virtual CPU for Java-based languages. The bottom tier, if you will. Or even better, the kernel of the popcorn. So how do we simply define the rest?

JRE (Java Runtime Environment)

Inside the JRE we find all of the software components necessary for running a Java application, including the JVM, requisite classes, and Properties file.

JDK (Java Development Kit)

The JDK is the provider of the JRE and Development tools that aid in developing, debugging, and executing a Java Program. Basically, it's the whole shebang! (not to be confused with a shebang line in python which is apparently a thing.)

There is more discussion to be had over the components of the JVM. But overall, having a general idea of the foundation you build on is very important. We're here to learn more than just code, after all. And if you've ever encountered the mention of any of the above, for instance, the garbage collector, now you understand what it is. So applaud yourself just for that!