Please support my sponors and make this site possible!!!
Please support our sponsors!

 

Home > Core Java FAQ > Java Virtual Machine FAQ 
Java Virtual Machine
 
Q .  What is Java VM? 

Ans : Java Virtual Machine (VM) is a software simulation of a computer which executes Java class codes. This is the basic building blocks for running Java programs, and is embedded in all Java capable web browsers, as well as Java Runtime Environment (JRE). 

You can download a Java Virtual Machine and its specification from JavaSoft's web site. 

Q . Why do I need Java VM? 

Ans : You will need to have Java VM installed on your system only if you want to use Timecruiser enhanced features such as RSVP, Registration, and Timecruiser HTML or JavaScript editions. 

These features use CGI scripts to invoke Java VM to process Timecruiser and related data. 

Q . Where can I download Java VM for my system?

Ans :  You can download JDK or JRE from the following sites. Java Download Sites Platform URL 

NT/Windows 95  
Sparc Solaris  
FreeBSD 
Linux
AIX 
AIX/PowerPC 
BSDI 
Digital/Unix 
HP 3000  
HP-UX 
IRIX/MIPS 
MacOS  
NetBSD  
Netware 
NeXTStep 
OpenBSD 
OS/2 
OS/390  
OSF/1 Alpha 
SCO 
SunOS 
UnixWare 
Q . How do I install Java VM for my system? 

Ans : For Windows user, JavaSoft is kind enough to package the JDK and JRE with InstallShield, simply download and invoke the executable and the install program will guide you throughout the whole process.  For other platforms, please read the installation guide for each platform. 

Q . What is JRE? 

Ans : JRE stands for Java Runtime Environment. This is a package introduced by JavaSoft to deliver Java computing environment in a minimal packaging. And is freely redistributable by software vendors like us. The size of JRE for Windows is about 2.6MB, and it uses InstallShield to ease the installation process. 

Q . What is the difference between Java VM and JRE? 

Ans : Java VM is considered part of the packaging in JRE. Java VM is used as the computing platform for all Java programs. JRE is a redistributable package for Java computing. Before JRE is available, JDK is the only package that contains a Java VM. 

Q . Where can I download JRE for my system? 

Ans : You can download JRE where you will find Java VM. Consult "Where can I download Java VM for my system?

Q . How do I install JRE on my system? 

Ans : The installation procedure is not different from that of JDK. Consult "How do I install Java VM on my system?" for detail. 

Q . What's the difference between web server Java extension and CGI invoked Java? 

Ans : Not all web servers provide Java extension. If your web server supports Java extension, that would generally mean that your web server can run Java classes directly in its process space. This is the fastest and most efficient way of using Java on the web server, although it is a bit restricted. 

CGI invoked Java is simply using web server's existing gateway which uses a script to externally run Java classes. It is less efficient but there is no restriction to this method as well as web server independent. 

Q . How can a Java program determine the level of JDK support given by the underlying VM? I.e. is it running in a JDK 1.0.2 or 1.1 VM?

Ans : Look at the java.version system property with:

String ver = System.getProperty("java.version");

There isn't a lot of standardization on the string contents however. Another possibility is to try { ... } to load a class that is unique to one release, like this:

boolean isJDK1_1 = true;
try {
   // java.awt.Cursor is available only in the 1.1.x JDK
   Class cls = Class.forName("java.awt.Cursor");
} catch (Exception e) {
   // we should have written 'ClassNotFoundException e',
   // but Communicator generates security exception instead.
   isJDK1_1 = false;
}

This approach has the advantage that it can be compiled by any version compiler.

Q . When, and by whom, is the main method of a class invoked?

Ans : 

Normally, you don't invoke main yourself; the Java Virtual Machine invokes it for you if it uses your class as its starting point of execution.

     A Java Virtual Machine always starts execution from the main method of some class. Even a large Java application, such as the HotJava™ browser, starts execution in one class's main method. The main method must be declared as public and static, it must have no return value, and it must declare a String array as its sole parameter:

     public static void main(String[] args) {
     	// ...
     }

You can include such a main method in any class you define. The Java compiler does not complain about classes containing unused main methods.
     How you as a user start a Java Virtual Machine can vary in different implementations. In some implementations, such as the JDK (1.0.2 and 1.1) on Solaris and Win32, you start the virtual machine with a command line that specifies a class and an optional list of strings for your program to start with. For example, suppose that your Java Virtual Machine is stored in a command named java, and you have written and compiled the following CountWords class:

     public class CountWords {
     	public static void main(String[] args) {
     		System.out.println(args.length);
     	}
     }

If you now issue the command:

     java CountWords argyle baldric corral delirium

the Java Virtual Machine starts up by seeking and loading your CountWords class, checking that it has an appropriate main method, and invoking that main method with an array of four strings ("argyle", "baldric", "corral", and "delirium") as its sole argument. In this example case, the main method merely prints out the number of strings in the argument String array.
     Most classes are never meant to provide the starting point for an application, but it is often useful to include a main method in them anyway. You can use main as a convenient way to test your class repeatedly as you develop it. When you later integrate your class into an application containing other classes, these extra main methods are automatically ignored, except for the single class you use as your application's starting point.

Q . What are bytecodes?

Ans : 

Java bytecodes are a language of machine instructions understood by the Java Virtual Machine and usually generated (compiled) from Java language source code.

     Java bytecodes encode instructions for the Java Virtual Machine. These instructions specify both operations and operands, always in the following format:

  • opcode (1 byte): specifies what operation to perform
  • operands (0-n bytes): specify data for the operation

     The 1-byte opcode is simply a number that the Java Virtual Machine interprets as a specific instruction. For instance, opcode value 104 (0x68 in hexadecimal representation) is the instruction to multiply two int values—it instructs the virtual machine to take the top two values off the Java operand stack, multiply them, and push the product back on the stack. In addition to its numerical value, each opcode has a conventional short name, called its mnemonic. The mnemonic for opcode 104 is imul.
     Following each opcode come any operands the opcode may require. The Java Virtual Machine uses the opcode to determine just how many following bytes are operands for that opcode. In some cases, such as the imul instruction, the opcode's single byte represents the entire instruction—no operands are needed. In other cases, the opcode may require one or more operands. For example, the fload instruction (opcode value 23, or 0x17 in hexadecimal) loads a float value from a local variable, and it uses an index operand to specify which local variable to load from. If the local variable of interest is at index 5, the complete instruction would have the following two bytes:

    23 5    [fload from local variable at index 5]

     There are different approaches for learning more about Java Virtual Machine instructions. If you want the comprehensive, detailed picture, read The Java Virtual Machine Specification (Tim Lindholm and Frank Yellin, 1996, Addison Wesley). It covers each virtual machine instruction—its name (mnemonic), what it does, what operands it takes, how it interacts with the operand stack, and more. It's not light reading, but it's a wonderful resource when you need it. You can also learn by experimentation, using javap

Q . What is javap?

Ans :   

The javap program is a class file disassembler that comes with the JDK (1.0.2 and 1.1).

The JDK (1.0.2 and 1.1) provides a Java class file disassembler, the javap program, which can translate from binary opcodes and operands to a human-readable format with opcode mnemonics, decimal numbers, and so on. javap is a simple, useful tool for exploring compiled class files and for learning about the Java Virtual Machine instruction set.
     The rest of this answer uses javap to explore the bytecodes generated from the following Java source file:

     public class BytecodeExample {
     	public float multiply(byte a, short b, int c, float d) {
     		return a * b * c * d;
     	}
     }

     After you compile this source file to a class file, run the javap program on the resulting class (use the -c option to see the virtual machine instructions):

     javap -c ByteCodeExample

(Note that you provide just the class name, not the full name of the file containing the class.) The output from this command on the JDK 1.1 includes the virtual machine instructions for the multiply method:

     Method float multiply(byte,short,int,float)
     	0 iload_1
	1 iload_2
	2 imul
	3 iload_3
	4 imul
	5 i2f
	6 fload 4
	8 fmul
	9 freturn

     Following are the same instructions, explained one by one; in each case the stack referred to is the Java operand stack.

iload_1 load int value of first method argument onto stack
iload_2 load int value of second method argument onto stack
imul take two int values from top of stack, multiply them, place product (int value) on stack
iload_3 load int value of third method argument onto stack
imul take two int values from top of stack, multiply them, place product (int value) on stack
i2f convert int value on top of stack to float value
fload 4 load float value of fourth method argument onto stack
fmul take two float values from top of stack, multiply them, place product (float value) on stack
freturn take float value from top of stack, return it as value from this method

     To appreciate the convenience provided by the javap program, consider the same 10 bytes of the multiply method in plain numerical (decimal) form:

     27  28  104  29  104  134  23  4  106  174
Q . What does it mean to say that Java is interpreted?

Ans :   

Several implementations of the Java Virtual Machine, including the JDK (1.0.2 and 1.1), interpret compiled Java code (virtual machine instructions)—for each instruction, the virtual machine carries out the specified behavior before reading the next instruction.

     Java technology uses both compilation and interpretation. Compilation is the process of translating content (such as code) from one language to another, and storing the results of that translation for later use. Many well-known programming languages, such as C, Pascal, and Fortran, are usually compiled straight from source code to native machine code. In contrast, the Java programming language is compiled into Java class files, which contain architecture-independent instructions for the Java Virtual Machine
     Interpretation also involves translating code from one language to another, except you directly execute the translation instead of storing it. Languages (or language families) such as Lisp and Basic are typically interpreted straight from source code to execution. In many Java implementations, interpretation picks up where compilation left off. Java Virtual Machine instructions, which were compiled from source code, are interpreted by the virtual machine—converted on the fly into native machine code, which is then executed rather than stored.
     Interpreting virtual machine instructions is common on existing implementations of the Java Virtual Machine (such as the JDK 1.0.2 and 1.1), but is not required by either The Java Language Specification or The Java Virtual Machine Specification. A virtual machine implementation may also use just-in-time (JIT) compilation: translating virtual machine instructions into native machine code at run time on the local platform, and then executing from that stored machine code. (It is even possible to have hardware that directly implements the Java Virtual Machine instruction set; such machines would then run compiled Java code natively.)
     Interpreted code is generally more flexible and adaptive than compiled code, but you usually pay a considerable price in execution speed because of the extra translation work performed as the program executes. This point is especially clear when you consider code with loops. The example below shows Java source code for a simple loop to sum integers from 1 to 1000:

     int sum = 0;
     for (int i = 1; i <= 1000; ++i) {
     	sum += i;
     }

After compilation into virtual machine instructions (and displayed by javap -c), the loop looks like:

	0 iconst_0
 	1 istore_1
	2 iconst_1
	3 istore_2
	4 goto 14
	7 iload_1
	8 iload_2
	9 iadd
	10 istore_1
	11 iinc 2 1
	14 iload_2
	15 sipush 1000
	18 if_icmple 7
	21 return

     Using just-in-time compilation, the above virtual machine instructions can be translated once into native machine code, and then the machine code is used directly each time through the loop. Using interpretation, on the other hand, means that the machine code for executing the loop is not stored for reuse—the virtual machine instructions are read and translated into machine code each time through the loop.

Q . What kind of garbage collection does the Java Virtual Machine use?

Ans : 

The Java Virtual Machine specification does not require any particular algorithm; the virtual machine implementation in the JDK 1.0.2 and 1.1 uses a partially conservative mark-and-sweep garbage collector, but other implementations may use other techniques.

     The Java Virtual Machine is required to provided automatic storage management for objects (class instances and arrays). In the JDK (1.0.2 and 1.1), for instance, storage space for all objects is allocated from a central Java heap, and a running Java program uses pointers into the heap area, called object references, to access its objects. When the program no longer holds a reference to an object, that object's space on the heap can be reclaimed, or garbage collected. Automatic garbage collection means that the run-time system, not the programmer, is responsible for tracking memory use and deciding when to free memory that is no longer needed. This strongly boosts programmer productivity and code robustness.
     A Java Virtual Machine implementation must include some form of garbage collection, but the implementation can choose what kind. The JDK (1.0.2 and 1.1) implements garbage collection with a partially conservative mark-and-sweep algorithm.
     A round of mark-and-sweep garbage collection starts by identifying any element in a running program (that is, any element on one of the the program's active thread execution stacks) that might refer to an object. For pure Java code, there is no question about precisely which elements are object references, but Java programs can also include non-Java native methods, which might have their own object pointers. The garbage collector is conservative in that it errs on the side of safety: if an element even looks like it might point to an object in the central heap, that element gets treated as an object reference. The garbage collector traces all potential references to corresponding objects on the heap, and from any references held by those objects to yet further objects, and so on. It marks all objects encountered in this transitive process; these objects are considered the program's set of live objects that must be maintained. Finally, the garbage collector scans (sweeps) the heap for all unmarked objects and reassigns their space back to the pool of free memory available for new allocation. Note that this method correctly picks up dead reference cycles (e.g., X refers to Y, which refers to Z, which refers to X, but the program no longer refers to any of the three), which escape detection by some other algorithms, such as simple reference counting.

Q . why does my finalize method never seem to get invoked?

Ans  : 

Your object's finalize method will get invoked, but the Java system makes no guarantees about when; it requires only that an object be finalized before it is garbage collected.

     Objects use system resources, and a well-behaved object should free its resources for reuse once the object is no longer needed. One system resource, storage space for objects, is managed automatically by the Java Virtual Machine: the virtual machine detects when an object is no longer usable and eventually reclaims the object's space for use by new objects. If your object uses any other system resource, such as a graphics context, an open file, or a network connection, it is up to you to explicitly manage that resource. Java's system of finalization provides a simple notification service with which you can define how your objects free up their resources.
     The core of Java's finalization system is the finalize method:

     protected void finalize() throws Throwable { ... }

     The Object class defines an empty version of this method, which you override in a subclass when you need to specify finalization actions for that class. The following code fragment illustrates a class that provides a method to explicitly clean up system resources, but also defines finalize as a backup measure:

     class MyClass {
     	AudioDevice device = AudioDevice.acquire();
     	void cleanUp() {
     	      // ...
	      if (device != null) {
                      device.release();
                      device = null;
                  }
              }

     	protected void finalize() throws Throwable {
     	      if (device != null) 
                      device.release();
                  }
                  super.finalize();
            }
           // ...
     }

     The most common confusion about finalization is when it occurs. There is much leeway—a virtual machine is required only to obey the following sequence:

  1. Your program removes its last reference to an object.
  2. The virtual machine invokes finalize on that object.
  3. The virtual machine garbage collects the object.

     What this means in practice, such as on the JDK 1.0.2 and 1.1 virtual machines, is that finalization waits for garbage collection, and then runs immediately prior to the actual reclamation of space. You can wait indefinitely for finalization to occur, because garbage collection usually waits until either the system runs low on memory or there is sufficient slack time in the application. If you need to, you can initiate finalization and garbage collection explicitly by invoking System.runFinalization() or System.gc(), but these methods provide no guarantees either. Finalization or garbage collection (depending on which method you invoke) will occur, but there is no guarantee that some specific object of yours is ready to be finished off.
     Because the timing of finalization is implementation dependent, and even circumstance dependent, you can't rely on finalization for consistent, timely behavior. Wherever possible, you should free critical system resources explicitly in your code and rely on finalization as more of a backup measure. The AWT code for the Graphics class (in JDK 1.0.2 and 1.1), for instance, disposes of each system graphics context explicitly as soon as it can; for safety, the class also invokes dispose from its finalize method:

     /* in Graphics.java (JDK 1.0.2 and 1.1): */    
     public void finalize() {
     	dispose();
     }
Q . I'm having trouble invoking methods on the objects returned from Class's forName method-how should I use Class.forName?

Ans : 

Invoke newInstance on the Class object returned by forName and then cast the resulting instance to a type that the compiler can access; only then can your program invoke a method on the instance of the newly loaded class.

     The forName method in class Class is a hidden gem in the Java system. This method lets your code create a new class type from a dynamic name—that is, a name given to your program as a string at run time. What's particularly powerful about using forName is that neither you nor the compiler needs to know the exact details of the new class, only what superclass it extends or interfaces it implements. The forName method is what enables a Java-capable browser, for instance, to load arbitrary applets, even though the browser can't know in advance what Applet subclasses it will be called on to create.
     The forName method takes a String argument as the name of a class, and attempts to create a binary representation for a class with that name. (This process is called class loading.) If it succeeds, it returns an instance of class Class that represents the newly created class type. The following code illustrates:

     Class newClass = null;  // initialize local variable, in case
                          // forName throws exception
     String packageName = "myPackage";
     String className = "myClass";
     try {
          newClass = Class.forName(packageName + "."  + className);
     } catch (ClassNotFoundException e) { /* ... */ }

     The Class instance returned by forName only represents the new class type; it is not an instance of that class. To obtain an instance of the new class, invoke newInstance on the Class object, which returns an object reference of type Object. (Note that newInstance requires that the target class have an accessible no-parameter constructor.) To access more than plain Object functionality, you need to cast the object reference to a more specific type—but what type?
     Although the forName method can create a new class type at run time, the way your code uses that class is still checked by the compiler, before your program has a chance to run. This restricts your code to using the new class and its instances only in terms of a superclass or interfaces that the compiler can check. For example, suppose that myPackage.myClass in the previous code fragment implements the Runnable interface, which contains the single method run. You can then cast the new instance to Runnable, after which the compiler will allow you to invoke run on it:

    Object foo = null;
     try {
          foo = (Runnable) newClass.newInstance();
          foo.run();  // invoke method on new instance
     } catch (IllegalAccessException e) { // ...
     } catch (InstantiationException e) { // ...
     }

Thus, the newly loaded class may have all kinds of wonderful functionality, but the compiler doesn't know this at compile time; the compiler lets your code access only those methods (and fields) belonging to an interface or superclass that it can check.

Q . Why do I get verifier errors when loading a class file produced by javac?

Ans : 

Chances are the class was compiled with optimization, which can cause the class file to fail verification; this is an unfortunate flaw in existing implementations.

     The Java Virtual Machine performs three general processes when it first attempts to execute code belonging to a class:

  1. loading: given the class name, determine the binary form for the class
  2. linking: convert the class's binary form so that it can be merged into the currently executing virtual machine
  3. initialization: execute the static initializers for the class and the class variable initializers

All three processes are managed by a class loader (an instance of a ClassLoader subclass). A Java program can have more than one class loader, to define different policies for finding classes and constraining their behavior.
     The process of linking usually starts with verification—checking that the class's binary representation is well formed and the virtual machine instructions in it obey the constraints of the Java language and Virtual Machine. Verification adds both security and robustness—it protects a virtual machine from malicious executable code, and it weeds out class files that may have been accidentally corrupted in transmission. An error detected during verification is thrown as an instance of the VerifyError class.
     The javac compiler is meant to generate only valid executable code, and should always do so when run in normal mode. However, when you compile with optimization (javac -O in the JDK 1.0.2 and 1.1), you run the risk of obtaining code that a verifier will not understand and will therefore reject.
     Java implementations have the leeway of omitting verification for trusted, local class files, and the JDK (1.0.2 and 1.1) takes advantage of this. The AppletViewer application, for instance, uses different class loaders for local classes versus classes loaded over the network. Its network class loader verifies each class as it comes in, but its local class loader omits the verification phase in order to save time. If you have a class file that loads successfully from the local file system, but fails when loaded over the network, you are quite likely seeing the difference between two class loaders, only one of which is using verification.
     You can test your own class files for well-formedness by using the javap tool in the JDK (1.0.2 and 1.1). When given the -verify option, javap simply runs the class you specify through its verifier and reports success or failure:

     % javap verify packageFoo.ClassE
     Class packageFoo.ClassE succeeds
Q . How fast are Java programs compared to equivalent C or C++ programs?

Ans : 

The relative speed depends on the type of program and on whether the virtual machine implementation uses interpretation or just-in-time compilation—GUI-intensive programs may have little noticeable difference, but computation-intensive programs run about 10-20 times slower in interpreted Java Virtual Machine instructions than in compiled native code.

     The execution speed of a Java program depends on how you run it. Most of the initial Java Virtual Machine implementations run interpretively—they translate Java Virtual Machine instructions to native machine code each time immediately prior to executing the code. Common estimates are that an interpretive virtual machine implementation runs around 10-20 times slower than comparable code compiled directly to the native platform.
     This slowdown represents the worst-case behavior for computation-bound programs, where intensive, uninterrupted computation comprises most or all of the program. GUI-dominated programs, on the other hand, typically spend most of their time waiting for user input; in such programs, the perceived difference in performance is often minor.
     If raw execution speed is the bottleneck, you might consider using a virtual machine implementation that includes a just-in-time (JIT) compiler, which are becoming more and more common. A JIT compiler translates Java Virtual Machine instructions into native machine code at run time on the local platform. Once the virtual machine implementation has this translation, it can run the native code at speeds comparable to other compiled languages.

 

Copyright © 2000 javafaq.com. All rights reserved