📄 ch07.html
字号:
<A NAME="pgfId-1087771"></A>Using Auto-Pilot</H5><P CLASS="Body"><A NAME="pgfId-1087772"></A>One little-known trick with <EM CLASS="CODE">jdb</EM> is the <EM CLASS="CODE">jdb</EM> startup file. In this file, <EM CLASS="CODE">jdb</EM> automatically looks for a file called <EM CLASS="CODE">jdb.ini</EM><A NAME="marker-1087773"></A><A NAME="marker-1087774"></A> in the <EM CLASS="CODE">user.home</EM> directory. If you have multiple projects, it is a good idea to set a different <EM CLASS="CODE">user.home</EM> property for each project when you start <EM CLASS="CODE">jdb</EM>. To start <EM CLASS="CODE">jdb</EM> with a <EM CLASS="CODE">jdb.ini</EM> file in the current directory, type the following: </P><PRE CLASS="CODE"><A NAME="pgfId-1087775"></A>jdb -J-Duser.home=.</PRE><P CLASS="Body"><A NAME="pgfId-1087776"></A>The <EM CLASS="CODE">jdb.ini</EM> file lets you set up <EM CLASS="CODE">jdb</EM> configuration commands, such as <EM CLASS="CODE">use</EM>, without having to enter the details each time a<A NAME="marker-1087777"></A> <EM CLASS="CODE">jdb</EM> runs. In the following example, <EM CLASS="CODE">jdb.ini</EM> file starts a <EM CLASS="CODE">jdb</EM> session for the <EM CLASS="CODE">FacTest</EM> class. It includes the Java platform sources on the source path list and passes the parameter <EM CLASS="CODE">6</EM> to the program. It then runs and stops at line 13, displays the free memory, and waits for further input. </P><PRE CLASS="CODE"><A NAME="pgfId-1087778"></A>load FacTeststop at FacTest:13use /home/calvin/java:/home/calvin/jdk/src/run FacTest 6memory</PRE><P CLASS="Body"><A NAME="pgfId-1087779"></A>Here is the output from the <EM CLASS="CODE">jdb.ini</EM> file execution: </P><PRE CLASS="CODE"><A NAME="pgfId-1087780"></A>$ jdb -J-Duser.home=/home/calvin/javaInitializing jdb...0xad:class(FacTest)Breakpoint set at FacTest:13running ...Free: 662384, total: 1048568main[1]Breakpoint hit: FacTest.compute (FacTest:13)main[1]</PRE><P CLASS="Body"><A NAME="pgfId-1087781"></A>You might wonder if <EM CLASS="CODE">jdb.ini</EM> files can be used to control an entire <EM CLASS="CODE">jdb</EM> session. Unfortunately, commands in a <EM CLASS="CODE">jdb.ini</EM> startup file are executed synchronously, and <EM CLASS="CODE">jdb</EM> does not wait until a breakpoint is reached before executing the next command. This makes printing variables awkward. You can add artificial delays with repeated help commands, but there is still no guarantee the thread will be suspended when you need it to be. </P></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087782"></A>Creating a Session Log</H5><P CLASS="Body"><A NAME="pgfId-1087786"></A><A NAME="marker-1087783"></A><A NAME="marker-1087784"></A><A NAME="marker-1087785"></A>You can use a little-known <EM CLASS="CODE">jdb</EM> feature to obtain a record of your debug session. The output is similar to what you see when you run <EM CLASS="CODE">jdb -dbgtrace</EM>. To enable <EM CLASS="CODE">jdb</EM> logging, create a file called <EM CLASS="CODE">.agentLog</EM> in the directory where you are running <EM CLASS="CODE">jdb</EM> or java <EM CLASS="CODE">-debug</EM>. In the <EM CLASS="CODE">.agentLog</EM> file, put the filename that you want the session information to be written to on the first line. For example, an <EM CLASS="CODE">.agentLog</EM> file would have these contents: </P><PRE CLASS="CODE"><A NAME="pgfId-1087787"></A>jdblog</PRE><P CLASS="Body"><A NAME="pgfId-1087790"></A>When you next run <EM CLASS="CODE">jdb</EM> or <A NAME="marker-1087788"></A><A NAME="marker-1087789"></A>java <EM CLASS="CODE">-debug</EM>, you will see <EM CLASS="CODE">jdb</EM> session information as shown below. You can use this information to retrieve the breakpoint hits and the commands entered if you need to reproduce this debug session. </P><PRE CLASS="CODE"><A NAME="pgfId-1087791"></A>---- debug agent message log ----</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087792"></A>[debug agent: adding Debugger agent to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087793"></A>[debug agent: adding Breakpoint handler to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087794"></A>[debug agent: adding Step handler to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087795"></A>[debug agent: adding Finalizer to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087796"></A>[debug agent: adding Reference Handler to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087797"></A>[debug agent: adding Signal dispatcher to system thread list] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087798"></A>[debug agent: Awaiting new step request] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087799"></A>[debug agent: cmd socket: Socket[addr=localhost/127.0.0.1, port=38986,localport=3 8985]] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087800"></A>[debug agent: connection accepted] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087801"></A>[debug agent: dumpClasses()] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087802"></A>[debug agent: no such class: HelloWorldApp.main] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087803"></A>[debug agent: Adding breakpoint bkpt:main(0)] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087804"></A>[debug agent: no last suspended to resume] </PRE><PRE CLASS="CODE"><A NAME="pgfId-1087805"></A>[debug agent: Getting threads for HelloWorldApp.main]</PRE></DIV></DIV><DIV><H4 CLASS="A"><A NAME="pgfId-1087807"></A><A NAME="46544"></A>Servlet Debugging</H4><P CLASS="Body"><A NAME="pgfId-1087810"></A><A NAME="marker-1087808"></A><A NAME="marker-1087809"></A>You can debug servlets with the same <EM CLASS="CODE">jdb</EM> commands you use to debug an applet or an application. The <A NAME="marker-1087811"></A>JavaServer™ Web Development Kit (JSWDK) provides a standalone program called <EM CLASS="CODE">servletrunner</EM><A NAME="marker-1087812"></A> that lets you run a servlet without a Web browser. On most systems, this program simply runs the java <A NAME="marker-1087813"></A><A NAME="marker-1087814"></A><EM CLASS="CODE">sun.servlet.http.HttpServer</EM> command. You can, therefore, start a <EM CLASS="CODE">jdb</EM> session with the <EM CLASS="CODE">HttpServer</EM> class. </P><P CLASS="Body"><A NAME="pgfId-1087815"></A>A key point to remember when debugging servlets is that Java Web Server and <EM CLASS="CODE">servletrunner</EM> achieve servlet loading and unloading by not including the <EM CLASS="CODE">servlets</EM> directory on the <EM CLASS="CODE">CLASSPATH</EM>. This means the servlets are loaded using a custom classloader and not the default system classloader. </P><DIV><H5 CLASS="B"><A NAME="pgfId-1087816"></A>Running <EM CLASS="B-code">servletrunner</EM> in Debug Mode</H5><P CLASS="Body"><A NAME="pgfId-1087818"></A><A NAME="marker-1087817"></A>In this example, the servlets examples directory is included on the <EM CLASS="CODE">CLASSPATH</EM>. You can configure the <EM CLASS="CODE">CLASSPATH</EM> for debug mode as follows: </P><DIV><H6 CLASS="D"><A NAME="pgfId-1087819"></A>Unix:</H6><PRE CLASS="CODE"><A NAME="pgfId-1087820"></A>ksh> export CLASSPATH=./lib/jsdk.jar:./examples:$CLASSPATH</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087821"></A>Windows:</H6><PRE CLASS="CODE"><A NAME="pgfId-1087822"></A>$ set CLASSPATH=lib\jsdk.jar;examples;%classpath%</PRE><P CLASS="Body"><A NAME="pgfId-1087824"></A><A NAME="marker-1087823"></A>To start the <EM CLASS="CODE">servletrunner</EM> program to debug <EM CLASS="CODE">SnoopServlet</EM>, either run the supplied startup script called <EM CLASS="CODE">servletrunner</EM> or just supply the <EM CLASS="CODE">servletrunner</EM> classes as a parameter to <EM CLASS="CODE">jdb</EM>. This example uses the parameter to <EM CLASS="CODE">servletrunner</EM>. </P><PRE CLASS="CODE"><A NAME="pgfId-1087825"></A>$ jdb sun.servlet.http.HttpServerInitializing jdb...0xee2fa2f8:class(sun.servlet.http.HttpServer)> stop in SnoopServlet.doGetBreakpoint set in SnoopServlet.doGet> runrun sun.servlet.http.HttpServerrunning ...main[1] servletrunner starting with settings:port = 8080backlog = 50max handlers = 100timeout = 5000servlet dir = ./examplesdocument dir = ./examples</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087826"></A>servlet propfile = ./examples/servlet.properties</PRE><P CLASS="Body"><A NAME="pgfId-1087827"></A>To run <EM CLASS="CODE">SnoopServlet</EM> in debug mode, enter the following URL in a browser where your machine is the machine at which you started <EM CLASS="CODE">servletrunner</EM> and <EM CLASS="CODE">8080</EM> is the port number displayed in the settings output. </P><PRE CLASS="CODE"><A NAME="pgfId-1087828"></A>http://yourmachine:8080/servlet/SnoopServlet</PRE><P CLASS="Body"><A NAME="pgfId-1087829"></A>In this example, <EM CLASS="CODE">jdb</EM> stops at the first line of the servlet's <EM CLASS="CODE">doGet</EM> method. The browser will wait for a response from your servlet until a timeout is reached. </P><PRE CLASS="CODE"><A NAME="pgfId-1087830"></A>main[1] SnoopServlet: initBreakpoint hit: SnoopServlet.doGet (SnoopServlet:45)</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087831"></A>Thread-105[1] </PRE><P CLASS="Body"><A NAME="pgfId-1087832"></A>We can use the <EM CLASS="CODE">list</EM> command to work out where <EM CLASS="CODE">jdb</EM> has stopped in the source. </P><PRE CLASS="CODE"><A NAME="pgfId-1087833"></A>Thread-105[1] list41 throws ServletException, IOException42 {43 PrintWriter out;44 45 => res.setContentType("text/html");46 out = res.getWriter ();47 48 out.println("<html>");49 out.println("<head> <title>Snoop Servlet </title></head>");Thread-105[1] </PRE><P CLASS="Body"><A NAME="pgfId-1087834"></A>The servlet can continue using the <EM CLASS="CODE">cont</EM> command. </P><PRE CLASS="CODE"><A NAME="pgfId-1087835"></A>Thread-105[1] cont</PRE></DIV></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087836"></A>Running Java Web Server in Debug Mode</H5><P CLASS="Body"><A NAME="pgfId-1087837"></A>The JWSDK release does not contain classes available in the Java Web Server and it also has its own special servlet configuration. If you cannot run your servlet from <EM CLASS="CODE">servletrunner</EM>, the other option is to run the<A NAME="marker-1087838"></A><A NAME="marker-1087839"></A> Java Web Server in debug mode. </P><P CLASS="Body"><A NAME="pgfId-1087840"></A>To do this add the <EM CLASS="CODE">-debug</EM> flag for the first parameter after the java program. For example in the script <EM CLASS="CODE">bin/js</EM> change the JAVA line to look like the following. In releases prior to the Java 2 platform release, you will also need to change the program pointed to by the variable <EM CLASS="CODE">$JAVA</EM> to <EM CLASS="CODE">java_g</EM> instead of java. </P><DIV><H6 CLASS="D"><A NAME="pgfId-1087841"></A>Before:</H6><PRE CLASS="CODE"><A NAME="pgfId-1087842"></A>exec $JAVA $THREADS $JITCOMPILER $COMPILER $MS $MX \</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087843"></A>After:</H6><PRE CLASS="CODE"><A NAME="pgfId-1087844"></A>exec $JAVA -debug $THREADS $JITCOMPILER $COMPILER $MS $MX \</PRE><P CLASS="Body"><A NAME="pgfId-1087846"></A><A NAME="marker-1087845"></A>Here is how to remotely connect to Java Web Server. The agent password is generated on the standard output from the Java Web Server so that it can be redirected into a file somewhere. You can find out where by checking the Java Web Server startup scripts. </P><PRE CLASS="CODE"><A NAME="pgfId-1087847"></A>jdb -host localhost -password <the agent password></PRE><P CLASS="Body"><A NAME="pgfId-1087848"></A>The servlets are loaded by a separate classloader if they are contained in the servlets directory, which is not on the <EM CLASS="CODE">CLASSPATH</EM> used when starting Java Web Server. Unfortunately, when debugging remotely with <EM CLASS="CODE">jdb</EM>, you cannot control the custom classloader and request it to load the servlet, so you have to either include the servlets directory on the <EM CLASS="CODE">CLASSPATH</EM> for debugging or load the servlet by requesting it through a Web browser and placing a breakpoint once the servlet has run. </P><P CLASS="Body"><A NAME="pgfId-1087851"></A><A NAME="marker-1087849"></A><A NAME="marker-1087850">
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -