Why the Java Virtual Machine Helps Your Code Run Better
Are you currently debating whether to use java for your next application, or use native toolkits and frameworks? Would you like to know what advantages java provides over native programming for an application? Read on to find out!
What Is a Native Application?
A native application is a program written specifically for an operating system (OS), and possibly for the specific hardware running that OS. It is mostly written in a language such as C/C++. The C/C++ source code is compiled to an object form using a compiler, which is then assembled into an executable by linking the required libraries. A program built this way will run on the specific hardware and OS it is built for, but may not work properly on other systems.
Why Aren’t Native Applications Portable?
A compiler for a language such as C/C++ translates source code statements into machine language for the targeted CPU. When you attempt to run this code on a different CPU, the program may not work correctly (or work at all) since the machine language instructions in the compiled code may not be supported by this CPU.
In addition, the new operating system may be different from the original one and may not even recognize the program file as an executable. This is due to different file formats used for executables across different operating systems (such as Windows, Linux, MacOS, etc.).
Portability is such a big issue with native applications that merely upgrading the compiler to the next version may introduce breaking changes. Your code may need to be fixed to work with the newer compiler. As such, splattering the source code with what are known as ifdef statements to isolate hardware-, OS-, or compiler-specific workarounds are common.
The following is a small code snippet from BZLib compression library which illustrates the use of ifdefs to isolate platform peculiarities:
#ifdef _WIN32 # include <windows.h> # ifdef small /* windows.h define small to char */ # undef small # endif # ifdef BZ_EXPORT # define BZ_API(func) WINAPI func # define BZ_EXTERN extern # else /* import windows dll dynamically */ # define BZ_API(func) (WINAPI * func) # define BZ_EXTERN # endif #else # define BZ_API(func) func # define BZ_EXTERN extern #endif
Source Code Portability Across Operating Systems
This situation can be alleviated to some extent by re-compiling the C/C++ source code to the new CPU. However, the operating system for the new CPU may be different. And the source code may not compile without changes, whether major or minor. Even minor changes in operating system versions may require some source code changes.
And when you consider dissimilar operating systems such as Windows and Linux/UNIX, portability is whole new ball game. Unless you are using a toolkit or a framework which completely isolates you from the operating system, source code portability is impossible. This is because the operating system interface is completely different between these systems. If you, in the remotest corners of your code, use any operating system primitives directly, then your code will not be portable across these diverse operating systems.
How Is Java Different?
It is in this scenario that java delivers a new paradigm, a new way of building software. When programming in java, you target a virtual machine. Such a machine exists as a concept, and the java language provides interfaces for programming against this machine. For example, you can query the quantity of memory available, the number of CPUs, the network interfaces, etc of the virtual machine.
How Are Java Applications Built?
The java language provides a java compiler which translates source code into object code. The object code is then executed by the java virtual machine, which is a separate program from the compiler. The operating system, in its turn, views the java virtual machine as just another program running on that OS.
The burden of portability has now shifted from the application programmer to the java virtual machine vendor. The application programmer writes the software using the primitives of the java language, and the java virtual machine is responsible for translating these primitives to the host operating system facilities. When a new version of the OS comes out, it is the vendor’s responsibility to update the java virtual machine so it works correctly on the new OS.
What Are the Advantages of the Java Virtual Machine?
As mentioned before, the java virtual machine provides a virtual view of the operating system and the hardware to the application programmer. This virtual view is in the form of various interfaces and methods, and serve to isolate the application programmer from the differences in the host OS and the underlying hardware. Thus, the application programmer can access facilities such as a Windowing Toolkit, Networking, 3D graphics, multiple CPUs, etc. without having to resort to low-level calls which end up making the program non-portable.
A java program is written and is compiled using the java compiler. The resultant object code (called byte code) can be transported to a different host operating system running on different hardware and should run without problems.
The java virtual machine uses a JIT compiler to optimize the byte code specifically for the target CPU. JIT stands for Just-in-Time and refers to the runtime optimizations that the JVM applies to the byte code to get it to run better on the current CPU.
Another advantage of using the Java Virtual Machine is that it can apply different optimizations for different use cases, all with the same byte code. For example, the Oracle JVM provides two options for running the byte code: a server mode and a client mode. The server mode optimizes for long running server programs, while the client JVM mode optimizes for quick response times since it is likely being used in interactive mode.
To summarize, a native application is built for a specific hardware and operating system. A java application, on the other hand, follows a Build Once Run Anywhere philosophy, by having a JVM run the compiled byte code instructions. While native applications have traditionally been viewed as more performant than java applications, it may not always be true due to the use of a JIT compiler by the JVM.
Have you developed a native application and had to change over to java due to portability? Or vice versa due to performance issues? Let us know in the comments below.
Image Credit: Profit_Image via Shutterstock.com