Some bugs are hard to replicate on your personal computer but easily replicated on production or test machines. It is a common situation that professional Java developers deal with frequently. To debug such problems, OpenJDK provides two tools, remote debugging
and jdb
.
This article focuses on jdb
.
For Java applications, typical production and test machines are Linux servers without display managers, so that only command line tools are available. Here we cannot use professional IDEs like IntelliJ IDEA, Eclipse, or Apache NetBeans IDE.
In such scenarios, we can use jdb
. jdb
is a command line debugger and it is part of the OpenJDK.
Troubleshoot Java with "jdb" Utility
jdb is available in the jdk/bin directory. It uses the Java Debug Interface (JDI) to launch and connect to the target JVM. The Java Debug Interface (JDI) provides a Java programming language interface for debugging Java programming language applications. JDI is a part of the Java Platform Debugger Architecture.
In this section, we will see how to attach jdb to java application and start debugging and monitoring.
jdb Command
This is format of the jdb command:
jdb [options] [classname] [arguments] options: This represents the jdb command-line options (e.g. attach, launch). classname: This represents the name of the main class to debug. arguments: This represents the arguments that are passed to the main() method of the class.
Sample Java App for Debugging
Following is a sample Java class we are going to debug and try to understand the different features available. It is important to compile this class with the "-g" option (javac -g Test.java), which generates all the debugging information including local variables. By default, only line number and source file information is generated.
public class Test { public static void main(String[] args) { System.out.println("First Line of main function"); System.out.println("Second Line of main function"); System.out.println("Third Line of main function"); int i=0; System.out.println("i: " + i); i = 2; System.out.println("i: " + i); while(true) { } } }
Attach jdb to the Java application
The command below is the most common way to start an application with the jdb debugger. Here we are not passing any jdb options, we have only passed the class name, which doesn't require any argument:
jdb Test
In this way, we start executing the main class "Test" in a similar way to how we start in a professional IDE. jdb stops the JVM before executing that class's first instruction.
Another way to use the jdb command is by attaching it to a JVM that's already running. The syntax for starting JVM with debugger port is:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 Test
To attach jdb with this remote jvm use below syntax:
jdb -attach 5005
In this article, we will not see remote debugging in detail.
Debugging and Monitoring
Following is the command to attach jdb with Java program Test:
/jdk/bin/jdb Test Initializing jdb ... >
Set a break point at line 5 using "stop", as follows:
> stop at Test:5 Deferring breakpoint Test:5. It will be set after the class is loaded. >
Start execution of application's main class using "run":
> run run Test Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint Test:5 Breakpoint hit: "thread=main", Test.main(), line=5 bci=0 5 System.out.println("First Line of main function");
Execute current line using "step":
main[1] step > First Line of main function Step completed: "thread=main", Test.main(), line=6 bci=8 6 System.out.println("Second Line of main function");
Execute current line using "step":
main[1] step > Second Line of main function Step completed: "thread=main", Test.main(), line=7 bci=16 7 System.out.println("Third Line of main function");
Printing local variable i using "print":
main[1] print i i = 0
Printing all local variables in current stack frame using "locals":
main[1] locals Method arguments: args = instance of java.lang.String[0] (id=841) Local variables: i = 0
Dump a thread's stack using "where":
main[1] where [1] Test.main (Test.java:10)
List threads in running application using "threads":
main[1] threads Group system: (java.lang.ref.Reference$ReferenceHandler)804 Reference Handler running (java.lang.ref.Finalizer$FinalizerThread)805 Finalizer cond. waiting (java.lang.Thread)806 Signal Dispatcher running (java.lang.Thread)803 Notification Thread running Group main: (java.lang.Thread)1 main running Group InnocuousThreadGroup: (jdk.internal.misc.InnocuousThread)807 Common-Cleaner cond. waiting
Continue execution from the breakpoint using cont
:
main[1] cont > i: 0 i: 2
All available commands in jdb using "help":
main[1] help
Command List
connectors -- list available connectors and transports in this VM run [class [args]] -- start execution of application's main class threads [threadgroup] -- list threads thread -- set default thread suspend [thread id(s)] -- suspend threads (default: all) resume [thread id(s)] -- resume threads (default: all) where [ | all] -- dump a thread's stack wherei [ | all]-- dump a thread's stack, with pc info up [n frames] -- move up a thread's stack down [n frames] -- move down a thread's stack kill -- kill a thread with the given exception object interrupt -- interrupt a thread print -- print value of expression dump -- print all object information eval -- evaluate expression (same as print) set = -- assign new value to field/variable/array element locals -- print all local variables in current stack frame classes -- list currently known classes class -- show details of named class methods -- list a class's methods fields -- list a class's fields threadgroups -- list threadgroups threadgroup -- set current threadgroup stop [go|thread] [] -- set a breakpoint -- if no options are given, the current list of breakpoints is printed -- if "go" is specified, immediately resume after stopping -- if "thread" is specified, only suspend the thread we stop in -- if neither "go" nor "thread" are specified, suspend all threads -- if an integer is specified, only stop in the specified thread -- "at" and "in" have the same meaning -- can either be a line number or a method: -- : -- .[(argument_type,...)] clear .[(argument_type,...)] -- clear a breakpoint in a method clear : -- clear a breakpoint at a line clear -- list breakpoints catch [uncaught|caught|all] | -- break when specified exception occurs ignore [uncaught|caught|all] | -- cancel 'catch' for the specified exception watch [access|all] . -- watch access/modifications to a field unwatch [access|all] . -- discontinue watching access/modifications to a field trace [go] methods [thread] -- trace method entries and exits. -- All threads are suspended unless 'go' is specified trace [go] method exit | exits [thread] -- trace the current method's exit, or all methods' exits -- All threads are suspended unless 'go' is specified untrace [methods] -- stop tracing method entrys and/or exits step -- execute current line step up -- execute until the current method returns to its caller stepi -- execute current instruction next -- step one line (step OVER calls) cont -- continue execution from breakpoint list [line number|method] -- print source code use (or sourcepath) [source file path] -- display or change the source path exclude [, ... | "none"] -- do not report step or method events for specified classes classpath -- print classpath info from target VM monitor -- execute command each time the program stops monitor -- list monitors unmonitor -- delete a monitor read -- read and execute a command file lock -- print lock info for an object threadlocks [thread id] -- print lock info for a thread pop -- pop the stack through and including the current frame reenter -- same as pop, but current frame is reentered redefine -- redefine the code for a class disablegc -- prevent garbage collection of an object enablegc -- permit garbage collection of an object !! -- repeat last command -- repeat command n times # -- discard (no-op) help (or ?) -- list commands dbgtrace [flag] -- same as dbgtrace command line option version -- print version information exit (or quit) -- exit debugger : a full class name with package qualifiers : a class name with a leading or trailing wildcard ('*') : thread number as reported in the 'threads' command : a Java(TM) Programming Language expression.
Most common syntax is supported.
Startup commands can be placed in either "jdb.ini" or ".jdbrc" in user.home or user.dir.
Quitting jdb:
quit
Conclusion
OpenJDK provides many amazing troubleshooting and diagnosis tools. These tools help you to fix issues in your production application quickly.
jdb
can be a great help when there is no way other than debugging the application and your favourite IDE is not available.
Knowing features like this helps you get the best java jobs, that's why to help you I wrote ebook 5 steps to Best Java Jobs.
Download this step-by-step guide for free!
[…] 25 июня в 10:31 Автор оригинала: Vipin Sharma Теги:toolsотладкаdebug Хабы: Java Отладка Всего голосов […]