Getting Readable Tracebacks

Problem

You’re getting an exception stack trace at runtime, but most of the important parts don’t have line numbers.

Solution

Disable JIT and run it again. Or use the current HotSpot runtime.

Discussion

When a Java program throws an exception, the exception propagates up the call stack until there is a catch clause that matches it. If none is found, the Java interpreter program catches it and prints a stack traceback showing all the method calls that got from the top of the program to the place where the exception was thrown. You can print this traceback yourself in any catch clause: the Throwable class has several methods called printStackTrace( ).

The Just-In-Time (JIT) translation process consists of having the Java runtime convert part of your compiled class file into machine language, so that it can run at full execution speed. This is a necessary step for making Java programs run under interpretation and still be acceptably fast. However, until recently its one drawback was that it generally lost the line numbers. Hence, when your program died, you still got a stack traceback but it no longer showed the line numbers where the error occurred. So we have the tradeoff of making the program run faster, but harder to debug. The latest versions of Sun’s Java runtime include the HotSpot Just-In-Time translator, which doesn’t have this problem.

If you’re still using an older (or non-Sun) JIT, there is a way around this. If the program is getting a stack traceback and you want to make it readable, you need only disable the JIT processing. How you do this depends upon what release of Java you are using. In the JDK 1.2 (Java 2), you need only set the environment variable JAVA_COMPILER to the value NONE, using the appropriate set command.

C:\> set JAVA_COMPILER=NONE     # DOS, MS-Windows
setenv JAVA_COMPILER NONE                # UNIX Csh
export JAVA_COMPILER=NONE     # UNIX Ksh, modern sh

To make this permanent, you would set it in the appropriate configuration file on your system; on Windows NT, you could also set this in the System Control Panel. You might well wish to make this setting the default, since using the JIT does take longer for startup, in return for faster execution. I ran JabaDex, my personal information manager application (see http://www.darwinsys.com/jabadex/) six times, thrice with JIT and thrice without; the results appear in Table 1-1.

Table 1-1. JIT and NOJIT timings

With JIT

NOJIT

46 seconds

34 seconds

37 seconds

28 seconds

34 seconds

29 seconds

Average: 39 seconds

Average: 30.3 seconds

As you can see, the average startup times are nearly 25% faster without JIT. Note that this includes reading a 500-line file and scanning it; that part of the code would definitely benefit from a JIT. Ideally we’d have selective control over JIT.

An easier way to disable JIT temporarily, and one that does not require changing the setting in your configuration files or Control Panel, is the -D command-line option, which updates the system properties. Just set java.compiler to NONE on the command line:

java -Djava.compiler=NONE  myapp

Note that the -D command-line option overrides the setting of the JAVA_COMPILER environment variable.

On earlier releases, there was a command-line flag -nojit, but this was discontinued in favor of the more verbose -D option.

As mentioned, Sun’s new HotSpot JIT -- included in many JDK 1.2 and JDK 1.3 releases -- generally provides tracebacks even with JIT mode enabled.

Get Java Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.