Debugging Using JDB
While testing your program, you may encounter errors ("bugs")
in one of two ways:
- the program may crash (throw an exception), or
- it may produce incorrect output.
In either case, you can use the debugger jdb
to help track down the error.
To learn about using jdb,
print and read the
JDB Quick Reference Guide.
Then try the two exercises below.
Example 1: Using jdb after a crash
- Create a new directory named DEBUG and copy into it the two files from
~cs367-2/public/JDB. To do this, type:
cd
cd private
mkdir DEBUG
cd DEBUG
cp ~cs367-2/public/JDB/* .
Be sure to type the dot at the end of the line!
The file Person.java
defines a very simple Person class, with a constructor that
initializes the person to be 10 years old, and an age method
that returns the person's current age.
The program in Bug.java
includes the declaration of a Person array.
It uses a loop to verify that everyone in the array has been
initialized to be 10 years old.
- Before you can compile and run Java programs, you need to set
up your environment so that the compiler can find the standard
Java classes.
To do this, change to your top-level directory by typing
Now edit your .cshrc.local file by typing
(be sure to include the dot as the first character of the file name).
Type:
setenv CLASSPATH ".:/s/jdk1.4.2_03/jre/lib/rt.jar"
followed by a newline (i.e., press the Enter key).
Write out the modified file by typing
and exit from emacs by typing
(Don't type the word "control-x", just hold down the ctrl
key while typing an x.)
Now type
Then go back to the directory you created in step 1.
- Compile your Java files by typing
- Run the Bug program (type:
java Bug).
This should cause a null pointer exception to be thrown.
If the error message does not tell you where the
exception occurred, run the program again as follows:
java -Djava.compiler=NONE Bug
This time you should see that the exception is thrown on line 10.
- Use jdb to find the problem. First type:
jdb Bug. When jdb is ready (it gives you a
">" prompt), tell it to stop at the beginning of the program
by typing: stop in Bug.main, then start the program
by typing: run Bug
- You should get a message saying that your breakpoint was hit.
- Now you can set another breakpoint at the statement that caused
the null pointer exception by typing: stop at Bug:10
(Note that when you set a breakpoint at a method, you must use
stop in
and a dot, while when you set a breakpoint at a line number you
must use stop at and a colon.)
Now let the program continue running until it gets to line 10, by
typing: cont
- The program will stop the first time it gets to line 10.
Type list to see line 10 and the surrounding lines.
You should see that line 10 is:
if (family[j].age() != 10) {.
A null pointer exception means that there was an attempt to
access a field or method of an Object whose value is null.
On line 10, the age method of family[j]
is being called. Is it possible that family[j] is null?
To see whether this is indeed the case, type:
print j (jdb should print j = 0), then type
print family[0].
You should find that indeed family[0] is null, so
it is wrong to try to call its age method.
- Look at the previous code that set the value of family.
Do you understand why family[0] (and all of the other
elements of the array) are null?
Example 2: Using jdb to understand bad output
- Exit from jdb by typing: quit.
Fix the problem you discovered in Example 1 by editing
Bug.java.
- Recompile Bug.java (type:
jikes -g Bug.java).
- Run Bug again.
It should not crash, but you should get lots of messages saying
that the people in the array are not 10 years old.
It seems that either the Person constructor method or its age method
is not working.
We can find out whether the Person constructor is working by
printing the value of a Person's myAge field after the
constructor has been called.
- Run jdb again (type: jdb Bug), and set a breakpoint
at the beginning of the program (stop in Bug.main).
Then start the program (run Bug).
- Use the list command to look at the code to see where
to set the next breakpoint.
Find the line number where you call the Person constructor, and
set a breakpoint there, then continue execution.
- Use the next command to execute the current line (the
call to the Person constructor).
- Use the print command to look at the value of
the Person's "myAge" field (print family[0].myAge).
- You should see that the value is 0, instead of 10 as expected.
- Look at the code for the Person constructor (unfortunately,
there doesn't seem to be a way to do this in jdb unless you
are currently stopped at a breakpoint that is in a Person method,
so you'll have to use a text editor in another window to look at
the code).
Can you find and fix the problem?