The Java Platform Debugger Architecture (JPDA) API included in the JDK lets you connect to a Java debug session and receive debug events. This code allows you to do the same things you would normally do with jdb or an IDE debugger. This is useful if you want to write your own debug, diagnostics or metrics tools.
Here is some sample code that will be debugged:
import java.util.Random; |
The plan is to monitor changes to the foo
member
variable.
NOTE: Sun JDK version 6 is used throughout.
Connecting to the VM
Different implementations provide different mechanisms for attaching to the VM via connectors. This allows users to connect by knowing the VM process ID (PID) or a TCP/IP host name and port, for example.
Here is the console output for performing the task using jdb
on Windows XP:
X:\Debug>start /MIN cmd /C java -Xdebug -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=y -cp .\bin Test X:\Debug>jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000 Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable Initializing jdb ... > VM Started: No frames on the current call stack main[1] watch Test.foo Deferring watch modification of Test.foo. It will be set after the class is loaded. main[1] resume All threads resumed. > Set deferred watch modification of Test.foo Field (Test.foo) is 0, will be 346777565: "thread=main", Test.main(), line=37 bci=26 main[1] exit X:\Debug>
The sequence of commands goes like this:
- Start the
Test
main class (the sample code) minimized in a new console (start /MIN cmd /C
) in debug mode (-Xdebug
). Have the VM listen on port 8000 (address=8000
). Wait for the debugger to attach before running (suspend=y
). - Start the debugger and attach to port 8000 (
hostname=localhost,port=8000
). Note the connector (com.sun.jdi.SocketAttach
). - Use
watch Test.foo
to start watching the field. - Use
resume
to tell the VM to resume. - Use
exit
to quit the debugger. Note that resume would have resumed until the field was hit again in the next iteration of the loop.
Using Java code to connect to the VM
In order to use the JPDA API,
you need to add the JDK tools.jar
to the classpath. It can
be found in the JDK lib
directory.
To interact with the VM, it is necessary to acquire a VirtualMachine object instance. The the same connector is used.
Code to connect to the VM:
public class VMAcquirer { |
For the sake of brevity I'm assuming that you can figure
out the com.sun.jdi
imports yourself.
Monitoring Test.foo
with code
Once a VirtualMachine
has been acquired, we can use
its EventRequestManager
to instruct it to notify us of events. For example, createClassPrepareRequests
can be used to instruct the VM to notify us when classes are loaded. The
VirtualMachine
EventQueue
is then used to process the generated events.
Code that monitors Test.foo
:
public class FieldMonitor { |
The above code is demo code and not very robust, though note it
allows that the Test
class might be loaded before or after
the VM is resumed.
Sample output when run against the test class:
com.sun.jdi.SocketAttach old=0 new=-301449374 old=-301449374 new=913937357 ...
I am getting connect refused. Any ideas ?
ReplyDeleteThis is not enough information to resolve the problem.
DeleteConsider posting the steps you have taken to stackoverflow.com along with details of your runtime environment.