a JVM implementation is an interpreter that converts a bytecode to machine code. But in the meantime a JVM implementation throws runtime error. Does it mean that an interpreter checks runtime error in Java? Or does it mean that Java's runtime occurs during the stage from bypecode to machine code?
It means that during run time of the application (when app was actually running) some exception was thrown eg attempt to divide by 0 which happen to be an user input.
After research, I've found that a classical compiler converts source code to machine code, ready for computer to execute it, while a classical interpreter directly execute source code.
In C, the compiler converts its source code to almost machine code (an object file). When we "run" a C program, it means the machine execute the object file. So the runtime error is thrown by the machine.
While in Java, the compiler converts its source code to bytecode, an intermediate code between source code and machine code. After compilation, an non-classical interpreter (an bytecode interpreter) directly executes this bytecode. So the runtime error is thrown by this kind of interpreter, which is called "virtual machine" in Java, as it acts like the machine in C which execute the program.
Return to the question I asked, the interpreter (JVM) in Java throws runtime error because it acts like machine itself rather than acting as an intermediate stage before the actual execution.
Related
Both Java and python (talking about CPython only) are interpreted to Java and CPython bytecode respectively. Both bytecodes are then interpreted by their respective virtual Machines (JVM & Cpython VM). (Here I am ignoring the JIT compilation part which kicks in after 10K runs.)
I have 2 questions regarding this:
Why does Java compilation to java bytecode take so much time as compared to python? In java, compilation is an explicit step while in python it happens at runtime.
Why is there no noticeable difference between the first run and the nth run of python when in the first run compilation to CPython bytecode is done and cached in .pyc files which is used in all successive runs. Is this bytecode compilation really an almost zero cost task in python?
Although it plays a big role in the runtime, I suppose static vs dynamic typing shouldn't play too big a role during the compilation and should not be the only reason for this difference in timings. Also, I think in both the implementations, some optimisation is done during the bytecode generation.
Is there something that I am missing here? (I do not have much experience working in Java.)
Update:
I actually did time profiling for python first run and later runs and found that statement 2 is wrong. There is a very noticeable difference when running a large python file.
Approach was simple. Created a large file with repeated lines of
a = 5
b = 6
c = a*b
print(str(c))
Then imported it to file large.py and ran time python large.py
First run result:
python large.py 1.49s user 0.33s system 97% cpu 1.868 total
Second run result:
python large.py 0.20s user 0.08s system 90% cpu 0.312 total
After deleting the __pycache__ folder:
python large.py 1.57s user 0.34s system 97% cpu 1.959 total
So basically in python also, the compilation to bytecode is a costly process, just that it's not as costly as in java.
The Java byte code compiler has to do a lot more checks than the Python byte code compiler. To illustrate, take this line from the "hello world" program:
System.out.println("Hello World!");
To compile this single line of code, the compiler has to find what all of its parts mean. This is more complicated than it sounds: System could be a package. Or it could be a class, either in the same package where the code is, or in one of the imported packages, or in java.lang. So the compiler has to check all of those options, in that order. Once it finds the System class, it has to check if its access modifiers permit this use.
After that, the compiler has to figure out what out is: is it a nested class, or a class member, and what are its access modifiers? The compiler finds that it's a static member variable, of the PrintStream type. Then it has to do the same checks for println. The compiler cannot emit any code for this line of code until it knows all of this because the generated byte code is different based on the types of the objects involved.
All these checks take time, most importantly because the compiler has to load a ton of class definitions from the standard library even for the most trivial program.
In comparison, the Python byte code compiler only needs to parse the line, and it can immediately generate code without looking at extra modules. In Python the code would be compiled to:
looking up a "System" object from the current scope (LOAD_NAME)
looking up an "out" attribute from System (LOAD_ATTR)
looking up "println" from "out" (LOAD_METHOD)
generate code to call it (CALL_METHOD)
The Python compiler doesn't care if some of these lookups failed at run time.
Another important difference is that the Java compiler is written entirely in Java, and compiled to machine code at run time, while much of CPython implementation is ahead-of-time compiled C code. This means Java has a bit of "cold start" problem compared to Python.
Update: Since Java 9, you can run a java program directly from source, without compiling it to byte code. Running a trivial "hello world" program gives you an idea of how much you save by compiling Java to byte code ahead of time, even for a trivial program:
The python program runs in 45-50 milliseconds as measured with time python hello.py.
The Java program without compiling to byte code ahead of time runs in 350-400 milliseconds as measured with time java Hello.java
The Java program after compiling to byte code runs in 70-80 milliseconds, as measured with time java Hello
Disclaimer: No scientific method followed or statistical analysis performed, so take this with a grain of salt. Test environment: Python version 3.8.5, Java version 11.0.8, on Fedora 32, with Intel i7 8750H CPU
hello.py:
print("hello world")
Hello.java:
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world");
}
}
I am confused that for in the role of the JVM. Is my understanding correct that JVM only converts the Bytecode to Machine code? So essentially there is communcation between the OS, JVM and CPU. My assumption is that the bytecode gets converted to Machine code and then processed by CPU.
JVM is a virtual machine.
Its like when you install some OS(Linux, Solaris) on VMware or VirtualBox, those are virtual machines. They run on top of the host OS.
JVM is different in a way that it's machine code is bytecode. There are machines which have high level languages as their machine code. If JVM were to run on the hardware and not on the host OS then it would expect a hardware capable of using bytecode instruction set.
However since it's runs on top of host OS, any bytecode instruction is communicated to the host after being converted to machine code. In case of VMware/VirtualBox, these softwares take care of it. In case of JVM it's done by JRE.
JAVA is a compiled and interpreted language and not only just the interpreted language. Lets see step by step execution of its program.
Suppose we write a java program and save it as “hello.java” in a folder somewhere on a hard disk.
The name of the java compiler is “javac”. For its compilation we have to write “javac hello.java” on the command line.
At this stage the high level code gets converted to the machine level code. Java converts it into a .class file as “hello.class” . This code is also known as a byte code because every instruction in this file is of 1 Byte.
This byte code can also be taken away on any other platform like
Mac, Linux or Windows. It only takes a JVM of respective OS for its
execution. Hence, JAVA is known as a first platform independent and
architecturally neutral language.
Now, for its execution, interpreter is used. It is named as a “java” itself. For its interpretation, “java hello.java” should be used on the command line. It internally invokes class loader which is responsible for loading the ‘hello.class’ file from hard disk to JVM’s address space.
Here there comes a ‘Byte code verifier’ which verifies the code to avoid run time failures. After successful verification, JVM executes the byte by byte code with the help of OS.
Thus the whole java program gets executed by JVM and OS. While JVM acts as a mini OS for the java program and it concerns OS only when the instructions are not in its scope.
I am a java beginner. i just read a line "
JVM (Java Virtual Machine) is an abstract machine." can anyone please help me to understand term abstract machine. what is abstract machine.
JVM = JAVA VIRTUAL MACHINE:- The word virtual itself indicates that it doesn't exists PHYSICALLY.
Elaborated here:
Abstract means HIDDEN.
When assembly programs runs on a computer, it is executed in the system runtime environment:
Properties
Platform dependent (if compiled for windows, a program will run only in windows not in Linux/UNIX etc.)
Not portable (same as above)
Systems runtime (in user's PC mainly under OS's control)
When Java Program runs into a computer, it is executed in another virtual machine (JVM) for which, the runtime environment is provided by JRE (JAVA Runtime Environment), it is installed automatically when you install JDK (Java Development Kit).
Without JRE, it is impossible to run Java Programs (Update: You can bundle your custom JRE with your code, in that case no need to install JDK or JRE separately but only in JDK9 & above)
This JVM itself runs in the system runtime (in user's PC/OS) but when Java program runs it is loaded into this running JVM.
For more practical AND visual experience:(for Windows only)
Open Task Manager
Go to Processes Tab
Find Java(TM) Platform SE Binary (This is JVM) - Java Instance
And now run a java program and write some code to delay the execution, like multi-threading with wait and notify (you can find such programs on google), due to this running program your Java Instance will show a little high memory and disk usage (not much high but slightly higher than that when no program was running in JRE/JVM). These processes you see in Task Manager, are running in System Runtime, and your Java program will not be listed there.
Instead it will be running inside this already running JRE.
This is the reason why JVM is ABSTRACT.
Now, do a little cross check and prove it..
Run 2-3 java programs, either keep them in longer waiting or just write Input Scanner and don't provide input, program will continue to run in blocking state so that we can see them later.
Once gain, confirm that only one instance of JVM/Java is running in task manager (Depends on how many JREs you have installed, sometimes IDEs can also create one instance, so better close it first for clear observation)
Now, where are those 2-3 Java Programs running?? Open VisualVM (it's under the same package/folder where your java executable resides)..
In this VisualVM, you can clearly see that, all your RUNNING Java Programs are listed.
Now, open side by side windows... Task Manager, VisualVM and one of your Running Code's Console.
Verify,
in Task manager - 1 instance of Java Binary.
in VisualVM - 3 different instances of your programs (if you run 3 java porgram)
Now, provide input in one of your code so that blocking state goes away and program terminates successfully.
Now verify,
in Task Manager - still 1 instance of Java Binary.
in VisualVM - 2 instances, because 1 code terminated/finished.
So, all your Java programs run under a Virtual Machine, a machine that is hidden, physically not available, abstract.
An abstract machine is a machine that does not have a physical existence.
Abstractness
A bicycle has a physical existence. I can touch it. It is not abstract.
A computer chip has a physical existence. I can touch it. It is not abstract.
A JVM is an executing program ... and has no physical existence. I cannot touch it. It is abstract.
Machine-ness:
A bicycle is a machine for transporting people.
A computer chip is a machine for executing programs that are coded in the instruction set of the chip; e.g. Intel x86 machine code.
A JVM is also a machine for executing programs that are coded in the instruction set of all JVMs; i.e. Java bytecodes.
Abstract machine means all of java application run in JVM and JVM runs in different platform as Window, Linux, Mac ...
JVM is interface to java application can run all platform
It is a bit philosophical question. When java application is compiled, the compiler produces its own "assembly" code that can not run directly on a hardware, it needs JVM. So, JVM creates an environment for java code similar to that of a machine. In other words from java perspective it is a machine, but in reality is a program that sits on top of a computer's operating system.
It means not real machine, however, it acts like a machine. Not any machine but as a machine called Central Processing Unit(CPU).
You could understand this like, whenever you write java program, you are writing instructions for a machine, but this machine is abstract, which is called Java Virtual Machine(JVM).
For each Operating system(OS) there is a Virtual Machine so that you do not have to write different versions of your java program to different OS.The JVM that you have in your JDK will handle the translation to each OS.
Your java program passes these steps to be understood by the underlying OS.
.java (Source file) gets compiled by compiler and becomes .class(class file) and this will be passed to JVM to be interpreted to machine language.
Class file is the one that has instructions for JVM
I would like to know what happens internally at the machine level when I try to run a java compiled file using the command "java class_name" If you know how the classes loaded into JVM will start executing with the help of Program Counter (PC) or any other pointers to the memory please explain it.
Like,
what loadClass() will do and its internal calls to findClass() and other methods. In that detail I am expecting the answer to be.
From Java doc
The java command starts a Java application. It does this by starting
a Java runtime environment, loading a specified class, and calling
that class's main method.
Read more.
I just wonder how can I get rid of the java jre dependency and produce native code and deliver the compiled code as the application?
So does it possible?
P.S. I know about gcj compiler is it what its doing ?
The compiled byte code will still depend on the java virtual machine. A JIT can't create code that "makes any sense" outside the JVM container. Yes, the result is a bunch of valid instructions for the target platform. But you still need the actual stack, heap and garbage collector (just to name a few required building blocks).
Excelsior has a very good Java2Native compiler. I would love to use it, but sadly our project takes 8 hours to compile with this compiler. The resulting speed of the app is impressive thought.
In theory, it's possible to take any interpreter for a language and turn it into a compiler that produces native code in that language. This is related to a series of equations called the Futamura projections. The high-level idea is essentially to "cheat" at how you define a compiler. Suppose that for some language L I have an interpreter I(p) that, given a program p written in language L, interprets that program. Now, I assume that interpreter I is represented directly in machine code. Further suppose that I have a program called mix that, given a machine code program and a sequence of input to that program, produces a new machine code program that is the initial program with its input fixed to be the specified input. For example, if I compiled this C++ program:
#include <iostream>
using namespace std;
int main() {
string message;
cin >> message;
cout << message << endl;
}
And then used mix to mix the program with the input "Hello," I'd get a program that always prints out the message "Hello". In other words, it would be as if I had written this program:
#include <iostream>
using namespace std;
int main() {
cout << "Hello" << endl;
}
It turns out that it's possible to build this program. I could do this, for example, by looking at the machine code, looking at every place that you try to read input from the console, and then replacing that with code that calls a function to instead read from a hardcoded string.
Now, consider what would happen if you were to run this mix program taking as input an interpreter I and some program p. Then the result of this would be a machine code program that is equivalent to the program I running on input p. In other words, you've just constructed a machine-code program that simulates what would happen if you were to run the interpreter on the program - which is a machine-code program that executes the program p!
Of course, this construction is completely impractical. To the best of my knowledge no one has written mix, and if they did, any program you made by turning an interpreter into a compiler would be woefully inefficient because it wouldn't be at all optimized.
As to your original question about whether you could take the JVM's JIT and use it to produce raw machine code for a Java program, I'm not sure since I haven't looked at the source code, but I strongly doubt it. The machine code almost certainly contains hooks that would call back into the JVM for specific tasks (for example, garbage collection, class loading, etc.), which would make the generated code not work in a standalone environment. However, it is a really cool idea to try to do this, and I hope that this answer shines some light on the theory behind it!
Please note that this question is similar to "Can I get rid of Windows and let my Windows program run on the bare metal without an operating system"?
Java programs expect a large set of classes to be readily available, which is what the JRE provides, and that any compiler or emulator will have to provide too.
What you can do however is to look at a launcher which will allow you to bring your own JRE with your application - this will only work at the platform of the JRE, but you are already willing to be platform specific. Several exist - I encourage you to look at the many questions already on Stack Overflow about how to do that.