The jdb
utility is included in the JDK as an example command-line debugger. The jdb
utility uses the Java Debug Interface (JDI) to launch or connect to the target JVM. The source code for jdb
is included in $JAVA_HOME/demo/jpda/examples.jar
.
The JDI is a high-level Java API that provides information useful for debuggers and similar systems that need access to the running state of a (usually remote) virtual machine. JDI is a component of the Java Platform Debugger Architecture (JPDA). See Java Platform Debugger Architecture.
The following sections provide troubleshooting techniques for jdb utility.
In JDI, a connector is the means by which the debugger connects to the target JVM. The JDK traditionally ships with connectors that launch and establish a debugging session with a target JVM, as well as connectors that are used for remote debugging (using TCP/IP or shared memory transports).
The JDK also ships with several Serviceability Agent (SA) connectors that allow a Java language debugger to attach to a crash dump or hung process. This can be useful in determining what the application was doing at the time of the crash or hang.
These connectors are SACoreAttachingConnector
, SADebugServerAttachingConnector
, and SAPIDAttachingConnector
.
These connectors are generally used with enterprise debuggers, such as the NetBeans integrated development environment (IDE) or commercial IDEs. The following sections demonstrate how these connectors can be used with the jdb
command-line debugger.
For detailed information about the connectors, see the Connection and Invocation Details from the JPDA documentation.
The command jdb -listconnectors
prints a list of the available connectors. The command jdb -help
prints the command usage help.
For more details on the jdb
utility, see the command man pages for:
Example 2-13 uses the SA PID Attaching Connector to attach to a process. The target process is not started with any special options; that is, the -agentlib:jdwp
option is not required. When this connector attaches to a process it does so in read-only mode: the debugger can examine threads and the running application, but it cannot change anything. The process is frozen while the debugger is attached.
The command in Example 2-13 instructs jdb
to use a connector named sun.jvm.hotspot.jdi.SAPIDAttachingConnector
. This is a connector name rather than a class name. The connector takes one argument named pid
, whose value is the process ID of the target process (9302
).
Example 2-13 jdb Connector for a PID
$jdb -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=9302
Initializing jdb ... >threads
Group system: (java.lang.ref.Reference$ReferenceHandler)0xa Reference Handler unknown (java.lang.ref.Finalizer$FinalizerThread)0x9 Finalizer unknown (java.lang.Thread)0x8 Signal Dispatcher running (java.lang.Thread)0x7 Java2D Disposer unknown (java.lang.Thread)0x2 TimerQueue unknown Group main: (java.lang.Thread)0x6 AWT-XAWT running (java.lang.Thread)0x5 AWT-Shutdown unknown (java.awt.EventDispatchThread)0x4 AWT-EventQueue-0 unknown (java.lang.Thread)0x3 DestroyJavaVM running (sun.awt.image.ImageFetcher)0x1 Image Animator 0 sleeping (java.lang.Thread)0x0 Intro running >thread 0x7
Java2D Disposer[1]where
[1] java.lang.Object.wait (native method) [2] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116) [3] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132) [4] sun.java2d.Disposer.run (Disposer.java:125) [5] java.lang.Thread.run (Thread.java:619) Java2D Disposer[1]up 1
Java2D Disposer[2]where
[2] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116) [3] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132) [4] sun.java2d.Disposer.run (Disposer.java:125) [5] java.lang.Thread.run (Thread.java:619)
In this example, the threads
command is used to get a list of all threads. Then a specific thread is selected with the thread 0x7
command, and the where
command is used to get a thread dump. Next, the up 1
command is used to move up one frame in the stack, and the where
command is used again to get a thread dump.
The SA Core Attaching Connector is used to attach the debugger to a core file. The core file might have been created after a crash, see Troubleshoot System Crashes. The core file can also be obtained by using the gcore
command on Oracle Solaris operating system or the gcore
command in gdb
on Linux. Because the core file is a snapshot of the process at the time the core file was created, the connector attaches in read-only mode: the debugger can examine threads and the running application at the time of the crash.
This command in Example 2-14 instructs jdb
to use a connector named sun.jvm.hotspot.jdi.SACoreAttachingConnector
. The connector takes two arguments: javaExecutable
and core
. The javaExecutable
argument indicates the name of the Java binary. The core
argument is the core file name (the core from the process with PID 20441 as shown in Example 2-14).
To debug a core file that has been transported from another machine, the operating system versions and libraries must match. In this case you can first run a proxy server called the SA Debug Server. Then, on the machine where the debugger is installed, you can use the SA Debug Server Attaching Connector to connect to the debug server.
In Example 2-15, there are two machines: machine1 and machine2. A core file is available on machine1 and the debugger is available on machine2. The SA Debug Server is started on machine1 as shown in Example 2-15.
The jsadebugd
command takes two arguments. The first argument is the name of the executable. Usually, this is java
, but it can be another name (in embedded VMs, for example). The second argument is the name of the core file. In this example, the core file was obtained for a process with PID 20441 using the gcore
utility.
On machine2, the debugger connects to the remote SA Debug Server using the SA Debug Server Attaching Connector, as shown in Example 2-16.
Example 2-16 Connect to Remote SA Debug Server
$ jdb -connect sun.jvm.hotspot.jdi.SADebugServerAttachingConnector:debugServerName=machine1
This command in Example 2-16 instructs jdb
to use a connector named sun.jvm.hotspot.jdi.SADebugServerAttachingConnector
. The connector has one argument, debugServerName
, which is the host name or IP address of the machine where the SA Debug Server is running.
Note: The SA Debug Server can also be used to remotely debug a hung process. In that case, it takes a single argument, which is the PID of the process. In addition, if it is required to run multiple debug servers on the same machine, each one must be provided with a unique ID. With the SA Debug Server Attaching Connector, this ID is provided as an additional connector argument. For more information on these and other related details, see the JPDA documentation. |