📄 ch07.html
字号:
code. This technique also saves you from adding and removing <EM CLASS="CODE">println</EM> debug statements and having to recompile your code.</P><P CLASS="Body"><A NAME="pgfId-1087499"></A>To use this technique, you have to set the debug flag to <EM CLASS="CODE">true</EM> and include application code to test that system property value. So, for example, you can set the debug flag to <EM CLASS="CODE">true</EM> and specify the <EM CLASS="CODE">TestRuntime</EM> program as follows:</P><PRE CLASS="CODE"><A NAME="pgfId-1087500"></A>java -Ddebug=true TestRuntime</PRE><P CLASS="Body"><A NAME="pgfId-1087501"></A>The source code for the <EM CLASS="CODE">TestRuntime</EM> class needs to examine this property and set the <A NAME="marker-1087502"></A><A NAME="marker-1087503"></A>debug <EM CLASS="CODE">boolean</EM> flag as follows:</P><PRE CLASS="CODE"><A NAME="pgfId-1087504"></A>public class TestRuntime {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087505"></A> boolean debugmode; //global flag that we test</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087506"></A> public TestRuntime () {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087507"></A> String dprop=System.getProperty("debug");</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087508"></A> if((dprop !=null) && (dprop.equals("yes"))){</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087509"></A> debugmode=true;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087510"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087511"></A> if(debugmode) {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087512"></A> System.err.println("debug mode!");</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087513"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087514"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087515"></A>}</PRE></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087516"></A>Creating Debug and Production Releases at Run Time</H5><P CLASS="Body"><A NAME="pgfId-1087517"></A>As mentioned earlier, one problem with adding <EM CLASS="CODE">System.out.println</EM> debug statements to your code is finding and removing them before you release the product. Apart from adding unnecessary code, <EM CLASS="CODE">println</EM> debug statements can contain information you do not want your customers to see.</P><P CLASS="Body"><A NAME="pgfId-1087522"></A><A NAME="marker-1087518"></A><A NAME="marker-1087519"></A><A NAME="marker-1087520"></A><A NAME="marker-1087521"></A>One way to remove <EM CLASS="CODE">System.out.println</EM> debug statements from your code is to use the following compiler optimization to remove predetermined branches from your code at compile time and achieve something similar to a debug preprocessor.</P><P CLASS="Body"><A NAME="pgfId-1087523"></A>This example uses a static <EM CLASS="CODE">dmode</EM> boolean flag that when set to <EM CLASS="CODE">false</EM> results in the debug code and the debug test statement being removed. When the <EM CLASS="CODE">dmode</EM> value is set to <EM CLASS="CODE">true</EM>, the code is included in the compiled class file and is available to the application for debugging purposes.</P><PRE CLASS="CODE"><A NAME="pgfId-1087524"></A>class Debug {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087525"></A> //set dmode to false to compile out debug code</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087526"></A> public static final boolean dmode=true;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087527"></A>}</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087528"></A> </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087529"></A>public class TestCompiletime {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087530"></A> if (Debug.dmode) { //These</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087531"></A> System.err.println("Debug message"); //are</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087532"></A> } //removed</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087533"></A>}</PRE></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087534"></A>Using Diagnostic Methods</H5><P CLASS="Body"><A NAME="pgfId-1087537"></A>You can use diagnostic methods to request debug information from the <A NAME="marker-1087535"></A><A NAME="marker-1087536"></A>Java virtual machine. The following two methods from the <EM CLASS="CODE">Runtime</EM> class trace the method calls and Java virtual machine byte codes that your application uses. Because both these methods produce a lot of output, it is best to trace very small amounts of code, even as little as one line at a time.</P><P CLASS="Body"><A NAME="pgfId-1087541"></A><A NAME="marker-1087538"></A><A NAME="marker-1087539"></A>To enable <A NAME="marker-1087540"></A>trace calls so you will see the output, you have to start the Java virtual machine with the <EM CLASS="CODE">java_g</EM><A NAME="marker-1087542"></A> or <EM CLASS="CODE">java -Xdebug</EM><A NAME="marker-1087543"></A> interpreter commands. To list every method as it is invoked at run time, add the following line before the code you wish to start tracing and add a matching <EM CLASS="CODE">traceMethodCalls</EM><A NAME="marker-1087544"></A> line with the argument set to <EM CLASS="CODE">false</EM> to turn the tracing off. The tracing information is displayed on the standard output.</P><PRE CLASS="CODE"><A NAME="pgfId-1087545"></A>//set boolean argument to false to disable</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087546"></A> Runtime.getRuntime().traceMethodCalls(true);</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087547"></A> callMyCode();</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087548"></A> Runtime.getRuntime().traceMethodCalls(false);</PRE><P CLASS="Body"><A NAME="pgfId-1087550"></A>You can also add the following line to your application to dump your own <A NAME="marker-1087549"></A>stack trace. You can find out how to read a <A NAME="marker-1087551"></A>stack trace in Analyzing Stack Traces (page XXX), but for now you can think of a stack trace as a snapshot of the current thread running in the Java virtual machine.</P><PRE CLASS="CODE"><A NAME="pgfId-1087552"></A>Thread.currentThread().dumpStack();</PRE></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087553"></A>Adding Debug Information</H5><P CLASS="Body"><A NAME="pgfId-1087555"></A><A NAME="marker-1087554"></A>Local variable information is not included in the core Java platform system classes. So, if you use a debug tool to list local variables for system classes where you place <EM CLASS="CODE">stop</EM> commands, you will get the following output, even when you compile with the <EM CLASS="CODE">-g</EM> flag as suggested by the output. This output is from a <EM CLASS="CODE">jdb</EM> session. The <EM CLASS="CODE">jdb</EM> command-line debugging tool is part of your JDK installation.</P><PRE CLASS="CODE"><A NAME="pgfId-1087556"></A>main[1] locals</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087557"></A>No local variables: try compiling with -g</PRE><P CLASS="Body"><A NAME="pgfId-1087558"></A>To get access to the local variable information, you have to obtain the source (<EM CLASS="CODE">src.zip</EM> or <EM CLASS="CODE">src.jar</EM>) and recompile it with a <EM CLASS="CODE">debug</EM> flag. You can get the source for most <EM CLASS="CODE">java.*</EM> classes with the binary downloads from <EM CLASS="CODE">java.sun.com </EM>(<EM CLASS="CODE">http://java.sun.com</EM>).</P><P CLASS="Body"><A NAME="pgfId-1087559"></A>Once you download the <EM CLASS="CODE">src.zip or src.jar</EM> file, extract only the files you need. For example, to extract the <EM CLASS="CODE">String</EM> class, type the following at the command line:</P><PRE CLASS="CODE"><A NAME="pgfId-1087560"></A>unzip /tmp/src.zip src/java/lang/String.java</PRE><P CLASS="Body"><A NAME="pgfId-1087561"></A>or</P><PRE CLASS="CODE"><A NAME="pgfId-1087562"></A>jar -xf /tmp/src.jar src/java/lang/String.java</PRE><P CLASS="Body"><A NAME="pgfId-1087564"></A><A NAME="marker-1087563"></A>Recompile the extracted class or classes with the <EM CLASS="CODE">-g</EM> option. You could also add your own additional diagnostics to the source file at this point.</P><PRE CLASS="CODE"><A NAME="pgfId-1087565"></A>javac -g src/java/lang/String.java</PRE><UL><P CLASS="NOTE"><A NAME="pgfId-1087566"></A>NOTE The Java 2 <EM CLASS="CODE">javac</EM> compiler gives you more options than just the original <EM CLASS="CODE">-g</EM> option for debug code, and you can reduce the size of your classes by using <EM CLASS="CODE">-g:none</EM><A NAME="marker-1087567"></A>, which gives you on average about a 10 percent reduction in size.</P></UL><P CLASS="Body"><A NAME="pgfId-1087570"></A><A NAME="marker-1087568"></A><A NAME="marker-1087569"></A>To run the application with the newly compiled debug class or classes, you need to use the <A NAME="marker-1087571"></A><EM CLASS="CODE">boot classpath</EM> option so that these new classes are picked up first. Type the following on one line with a space before <EM CLASS="CODE">myapp</EM>.</P><DIV><H6 CLASS="D"><A NAME="pgfId-1087572"></A>Win95/NT Java 2 platform:</H6><P CLASS="Body"><A NAME="pgfId-1087573"></A>This example assumes the Java platform is installed in <EM CLASS="CODE">c:\java</EM> and the source files are in <EM CLASS="CODE">c:\java\src</EM>:</P><PRE CLASS="CODE"><A NAME="pgfId-1087576"></A>jdb -<A NAME="marker-1087574"></A><A NAME="marker-1087575"></A>Xbootclasspath:c:\java\src;c:\java\jreiibt.jar;c: \java\jre\i18n.jar;. myapp</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087577"></A>Unix systems:</H6><P CLASS="Body"><A NAME="pgfId-1087578"></A>This example assumes the Java platform is installed in <EM CLASS="CODE">c:\java</EM> and the source files are in <EM CLASS="CODE">c:\java\src</EM>.</P><PRE CLASS="CODE"><A NAME="pgfId-1087579"></A>jdb -Xbootclasspath:/usr/java/src;/usr/java/jre/lib/rt.jar;/usr/java/jre/i18n.jar;. myapp</PRE></DIV></DIV></DIV><DIV><H4 CLASS="A"><A NAME="pgfId-1087581"></A><A NAME="17119"></A>Running Tests and Analyzing</H4><P CLASS="Body"><A NAME="pgfId-1087582"></A>If you are still having problems even after you have ruled out installation and environment problems and included debugging code, it is time to use tools to test and analyze your program. </P><DIV><H5 CLASS="B"><A NAME="pgfId-1087584"></A><A NAME="23861"></A>Getting Behind the Seat with <EM CLASS="C-Code">jdb</EM></H5><P CLASS="Body"><A NAME="pgfId-1087587"></A><A NAME="marker-1087585"></A><A NAME="marker-1087586"></A>Although there are some very good Integrated Development Environment (IDE) tools on the market, the Java debugger tool, <EM CLASS="CODE">jdb</EM> and its successors, have an important role to play in testing and debugging programs. Some advantages of <EM CLASS="CODE">jdb</EM> over IDE tools are it is free, it is platform independent (some IDE tools are not), and it runs as a separate process to the program being debugged. The benefit to <EM CLASS="CODE">jdb</EM> running as a separate process is that you can attach a debug session to a running program. </P><P CLASS="Body"><A NAME="pgfId-1087588"></A>The downsides to using <EM CLASS="CODE">jdb</EM> are it has only a command-line interface, and it relies on the same code you are trying to debug. This means if there is a bug in the <A NAME="marker-1087589"></A>Java virtual machine, <EM CLASS="CODE">jdb</EM> could break attempting to diagnose that same bug! </P><P CLASS="Body"><A NAME="pgfId-1087591"></A>The new <A NAME="marker-1087590"></A>JBug architecture was created to solve these problems in <EM CLASS="CODE">jdb</EM>. JBug, among other things, provides a debugger helper API in the <A NAME="marker-1087592"></A>Java virtual machine called the <A NAME="marker-1087593"></A>Java Virtual Machine Debug Interface (JVMDI). This helper communicates with the debugging front end using the J<A NAME="marker-1087594"></A>ava Debug Wire Protocol (JDWP). The debugging front end uses the remote <A NAME="marker-1087595"></A>Java Debug Interface (JDI) to send and receive commands over the Java Debug Wire Protocol. <EM CLASS="CODE">JBug</EM> is available for Java 2 platforms and has a <EM CLASS="CODE">jdb</EM>-style front end that you will learn more about below. </P></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087596"></A>Simple <EM CLASS="B-code">jdb</EM> Test Drive</H5><P CLASS="Body"><A NAME="pgfId-1087597"></A>Back to the classic <EM CLASS="CODE">jdb</EM> tool. Here are some simple steps to analyze a program using <EM CLASS="CODE">jdb</EM>. This first example debugs a program from application startup. The Remote Debugging example (page 222) explains how to connect to a running program. </P><P CLASS="Body"><A NAME="pgfId-1087599"></A><EM CLASS="Bold">Start the Session. </EM>To begin the debug session, compile the <EM CLASS="CODE">SimpleJdbTest</EM><A NAME="marker-1087598"></A> program below with full debugging information using <EM CLASS="CODE">javac</EM> and the <EM CLASS="CODE">-g</EM> <EM CLASS="CODE">debug</EM> flag. In this example, the <EM CLASS="CODE">SimpleJdbTest.java</EM> program is an application, but it could just as well be an applet. The procedures for debugging applications with <EM CLASS="CODE">jdb</EM> are the same for debugging applets once the debug session has started. </P><DIV><H6 CLASS="D"><A NAME="pgfId-1087600"></A><EM CLASS="C-Code">SimpleJdbTest</EM><EM CLASS="Bold"> program:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087601"></A>import java.awt.*;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087602"></A>import java.awt.event.*;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087603"></A> </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087604"></A>public class SimpleJdbTest extends Frame{</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087605"></A> Panel p;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087606"></A> Button b[]=new Button[2];</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087607"></A> int counter=0;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087608"></A> </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087609"></A> SimpleJdbTest() {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087610"></A> setSize(100,200);</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087611"></A> setup();</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087612"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087613"></A> void setup (){</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087614"></A> p=new Panel();</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087615"></A> b[0]= new Button("press");</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087616"></A> p.add(b[0]);</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087617"></A> add(p);</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087618"></A> b[0].addActionListener( new ActionListener() {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087619"></A> public void actionPerformed(ActionEvent e) {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087620"></A> counter++;</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087621"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087622"></A> });}</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087623"></A> public static void main(String args[]) {</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087624"></A> SimpleJdbTest sjb=new SimpleJdbTest();</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087625"></A> sjb.setVisible(true);</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087626"></A> }</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087627"></A>}</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087628"></A><EM CLASS="Bold">Compile </EM>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -