Java was publicly released in 1996. At that time, C++ substantially dominated the market and was widely used for creating many kinds of software applications. One of the primary goals for developing a new language like “JAVA” was the need for an appropriate language in developing embedded device applications. Programming for embedded devices also demands portability, and these devices typically use a wide variety of CPUs and different architectures.

Each architecture made C++ applications behave differently and typically needed to be rewritten for new devices. The complexity of managing multiple build environments and codebases was the biggest challenge in supporting multi-device development. Java was an attempt to create a higher-level language that eliminated these problems—and it largely succeeded in its attempt. It eliminated the multi-device development problems with the introduction of a virtual machine (VM) and portable bytecode architecture. Sun Microsystems aptly came up with the marketing slogan “Write Once, Run Anywhere.”

A Java compiler translates the Java source program into what is known as bytecode, which is similar to the OBJ code generated by a C++ compiler or any other language compiler. The only difference is that most of these compilers generate the object code for a real CPU, whereas the bytecode generated by a Java compiler consists of the instructions for a “pseudo CPU.” In other words, whereas C++ OBJ code consists of the instruction set for, say, an Intel 80x86 CPU or Motorola 68xxx CPU, or maybe even a SPARC workstation, Java bytecode represents an instruction set for a CPU that does not exist in reality. What Sun Microsystems did was to create a virtual CPU in memory, and they designed an instruction set for this virtual CPU, which itself is emulated in memory at runtime.

A Java virtual machine (JVM) emulates the aforementioned virtual CPU. The JVM provides the runtime environment for a Java executable (bytecode). It also provides a bytecode interpreter and a verifier that confirms the bytecode’s validity before translating and running it on a real CPU. In addition, it has several more modules for security, memory and thread management, and other purposes. A JVM is essentially a machine (as its name suggests) that is capable of running a Java executable.

The Java compiler stores the generated bytecode in a file with the extension .class. Our program will also use several .class files supplied by the Java Development Kit (JDK). The class loader in JVM loads these .class files in memory. Along with our .class files, JVM also loads other library files required by our application at the runtime. The JVM subjects the loaded classes to verification to ensure that they do not contain any undefined instructions for the pseudo CPU. The internal .class files need not go through such verifications. If the bytecode of our application program contains an invalid instruction, the JVM rejects its execution and unloads it from memory. After the code is verified, a built-in interpreter converts it to machine code. Now, the code is handed over to the execution unit to be run on the host.

  Modified On Nov-27-2017 02:21:23 PM

Leave Comment