📄 ch07.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"><HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-8859-1"><META HTTP-EQUIV="Content-Style-Type" CONTENT="text/css"><META NAME="GENERATOR" CONTENT="Adobe FrameMaker 6.0/HTML Export Filter"><LINK REL="STYLESHEET" HREF="CH07.css" CHARSET="ISO-8859-1" TYPE="text/css"><TITLE> Covered in this Chapter</TITLE></HEAD><BODY BGCOLOR="#ffffff"><P CLASS="CT"><A NAME="pgfId-1087399"></A>7</P><P CLASS="CT"><A NAME="pgfId-1087400"></A>Debugging Applets, Applications, and Servlets</P><P CLASS="Body"><A NAME="pgfId-1087401"></A>An unwritten law of programming states you will spend 10 percent of your time on the first 90 percent of a project, and the other 90 percent of your time on the remaining 10 percent. If this sounds like any of your projects, you are probably spending 90 percent of your time on debugging and integration. While there are plenty of books and people to help you start a project, there are far fewer resources available to help you finish it. </P><P CLASS="Body"><A NAME="pgfId-1087402"></A>The good news is that this chapter focuses completely on debugging and fixing to get your project out on time. This chapter and Chapter 8, Performance Techniques, depart from the auction application and use simple examples to walk you through the steps to debugging, fixing, and tuning your programs. </P><P CLASS="Body"><A NAME="pgfId-1087403"></A>By the time you finish this chapter, you should be an expert at troubleshooting programs written in the Java programming language--applets, applications, and servlets--of all shapes and sizes.</P><DIV><H4 CLASS="A"><A NAME="pgfId-1087404"></A>Covered in this Chapter</H4><UL><LI CLASS="BL"><A NAME="pgfId-1087405"></A>In a Rush? (page 210)</LI><LI CLASS="BL"><A NAME="pgfId-1087406"></A>Collecting Evidence (page 210) </LI><LI CLASS="BL"><A NAME="pgfId-1087407"></A>Running Tests and Analyzing (page 216)</LI><LI CLASS="BL"><A NAME="pgfId-1087408"></A>Servlet Debugging (page 226)</LI><LI CLASS="BL"><A NAME="pgfId-1087409"></A>Abstract Window Toolkit Debugging (page 229)</LI><LI CLASS="BL"><A NAME="pgfId-1087410"></A>Analyzing Stack Traces (page 231)</LI><LI CLASS="BL"><A NAME="pgfId-1087411"></A>Stack Trace Examples (page 240)</LI><LI CLASS="BL"><A NAME="pgfId-1087412"></A>Version Issues (page 244)</LI></UL></DIV><DIV><H4 CLASS="A"><A NAME="pgfId-1087414"></A><EM CLASS="A">I</EM><A NAME="32975"></A>n a Rush?</H4><P CLASS="Body"><A NAME="pgfId-1087415"></A>If you have a pressing problem you need an answer to right now, this table might help. It tells you where to find answers for common problems so that you can go directly to the information.<EM CLASS="A"></EM></P><TABLE><TR><TH ROWSPAN="1" COLSPAN="1"><P CLASS="TCH"><A NAME="pgfId-1087418"></A>Problem</P></TH><TH ROWSPAN="1" COLSPAN="1"><P CLASS="TCH"><A NAME="pgfId-1087420"></A>Section</P></TH></TR><TR><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087422"></A>Program hangs or crashes </P></TD><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087424"></A>Analyzing Stack Traces (page 231)</P></TD></TR><TR><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087426"></A>Problem in a running program </P></TD><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087428"></A>Getting Behind the Seat with <EM CLASS="CODE">jdb</EM> (page 216)</P></TD></TR><TR><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087430"></A>Java Web Server problems </P></TD><TD ROWSPAN="1" COLSPAN="1"><P CLASS="TB"><A NAME="pgfId-1087432"></A>Servlet Debugging (page 226) and</P><P CLASS="TB"><A NAME="pgfId-1087433"></A>Analyzing Stack Traces (page 231)</P></TD></TR></TABLE></DIV><DIV><H4 CLASS="A"><A NAME="pgfId-1087436"></A><A NAME="20165"></A>Collecting Evidence</H4><P CLASS="Body"><A NAME="pgfId-1087437"></A>The first step in trying to solve any problem is to gather as much evidence and information as possible. If you can picture a crime scene, you know that everything is checked, cataloged, and analyzed before any conclusions are reached. When debugging a program, you do not have weapons, hair samples, or fingerprints, but there is plenty of evidence you can gather that might contain or ultimately lead to the solution. This section explains how to gather that evidence. </P><DIV><H5 CLASS="B"><A NAME="pgfId-1087438"></A>Installation and Environment</H5><P CLASS="Body"><A NAME="pgfId-1087441"></A><A NAME="marker-1087439"></A><A NAME="marker-1087440"></A>The Java platform is a fast-moving and changing technology. You might have more than one release installed on your system, and those releases might have been installed as part of another product installation. In an environment with mixed releases, a program can experience problems due to changes to the platform in a new version or release. </P><P CLASS="Body"><A NAME="pgfId-1087442"></A>For example, if classes, libraries, or Windows registry entries from previous installations remain on your system after an upgrade, there is a chance the new software mix is causing your problems and needs to be investigated and ruled out. Opportunities for problems related to mixed software releases have increased with the use of different release tools to deliver the Java platform software. </P><P CLASS="Body"><A NAME="pgfId-1087443"></A>The section on Version Issues at the end of this chapter provides a complete list of major Java platform release and version information to help you rule out software release issues. This next section highlights the most common problems you are likely to encounter. </P></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087444"></A><EM CLASS="B-code">CLASSPATH</EM></H5><P CLASS="Body"><A NAME="pgfId-1087447"></A><A NAME="marker-1087445"></A>In the Java 2 platform, the <EM CLASS="CODE">CLASSPATH</EM><A NAME="marker-1087446"></A> environment variable is needed to specify the application's own classes only, and not the Java platform classes as was required in earlier releases. So it is possible your <EM CLASS="CODE">CLASSPATH</EM> environment variable is pointing at Java platform classes from earlier releases and causing problems. To examine the <EM CLASS="CODE">CLASSPATH</EM>, type the following at the command line for your operating system. </P><DIV><H6 CLASS="D"><A NAME="pgfId-1087448"></A><EM CLASS="D-Code">Windows 95/98/NT:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087449"></A><EM CLASS="TT">echo %CLASSPATH%</EM> </PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087450"></A><EM CLASS="D-Code">Unix systems:</EM></H6><PRE CLASS="CODE"><A NAME="pgfId-1087451"></A><EM CLASS="TT">echo $CLASSPATH</EM></PRE><P CLASS="Body"><A NAME="pgfId-1087453"></A><A NAME="marker-1087452"></A>Java classes are loaded on a first-come, first-served basis from the <EM CLASS="CODE">CLASSPATH</EM> list. If the <EM CLASS="CODE">CLASSPATH</EM> variable contains a reference to a <EM CLASS="CODE">lib/classes.zip</EM> file, which in turn points to a different Java platform installation, this can cause incompatible classes to be loaded. </P><UL><P CLASS="NOTE"><A NAME="pgfId-1087455"></A>NOTE <EM CLASS="Note"></EM><A NAME="marker-1087454"></A>In the Java 2 Platform, the system classes are chosen before any class on the <EM CLASS="CODE">CLASSPATH</EM> list, to minimize the possibility of any old broken Java classes being loaded instead of a Java 2 class of the same name. </P></UL><P CLASS="Body"><A NAME="pgfId-1087456"></A>The <EM CLASS="CODE">CLASSPATH</EM> variable can get its settings from the command line or from configuration settings such as those specified in the User Environment on Windows NT, an <EM CLASS="CODE">autoexec.bat</EM> file, or a shell startup file like <EM CLASS="CODE">.cshrc</EM> on Unix. </P><P CLASS="Body"><A NAME="pgfId-1087462"></A><A NAME="marker-1087457"></A><A NAME="marker-1087458"></A><A NAME="marker-1087459"></A><A NAME="marker-1087460"></A><A NAME="marker-1087461"></A>You can control the classes the Java virtual machine uses by compiling your program with a special command-line option that lets you supply the <EM CLASS="CODE">CLASSPATH</EM> you want. The Java 2 platform option and parameter is <EM CLASS="CODE">-Xbootclasspath</EM><A NAME="marker-1087463"></A> classpath, and earlier releases use <EM CLASS="CODE">-classpath</EM> <A NAME="marker-1087464"></A><A NAME="marker-1087465"></A>classpath and <EM CLASS="CODE">-sysclasspath</EM><A NAME="marker-1087466"></A> classpath. Regardless of which release you are running, the <EM CLASS="CODE">classpath</EM> parameter specifies the system and user classpath, and zip or Java Archive (JAR) files to be used in the compilation. </P><P CLASS="Body"><A NAME="pgfId-1087467"></A>As an example, to compile and run the <EM CLASS="CODE">Myapp</EM> program with a system <EM CLASS="CODE">CLASSPATH</EM> supplied on the command line, use the Windows or UNIX instructions that follow depending on your platform. </P></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087468"></A><EM CLASS="D-Code">Windows 95/98/NT:</EM></H6><P CLASS="Body"><A NAME="pgfId-1087469"></A>In this example, the Java platform is installed in the <EM CLASS="CODE">C:\java</EM> directory. Type everything on one line. The <EM CLASS="CODE">-J</EM> option lets you pass extra conditions to the compiler. </P><PRE CLASS="CODE"><A NAME="pgfId-1087470"></A>javac -J -Xbootclasspath:c\javaiib\tools.jar; c:\java\jre\iib\rt.jar;c:\java\jre\iib\i18n.jar;.Myapp.java</PRE><P CLASS="Body"><A NAME="pgfId-1087471"></A>You do not need the <EM CLASS="CODE">-J</EM> run-time flag to run the compiled <EM CLASS="CODE">Myapp</EM> program; just type the following on one line: </P><PRE CLASS="CODE"><A NAME="pgfId-1087472"></A>java -Xbootclasspath:c:\java\jre\iib\rt.jar; c:\java\jre\iib\i18n.jar;. Myapp</PRE></DIV><DIV><H6 CLASS="D"><A NAME="pgfId-1087473"></A>Unix systems: </H6><P CLASS="Body"><A NAME="pgfId-1087474"></A>In this example, the Java platform is installed in the <EM CLASS="CODE">/usr/local/java</EM> directory. Type everything on one line: </P><PRE CLASS="CODE"><A NAME="pgfId-1087475"></A>javac -J-Xbootclasspath:/usr/local/java/lib/tools.jar:/usr/local/java/jre/lib/rt.jar:/usr/local/java/jre/lib/i18n.jar:. Myapp.java</PRE><P CLASS="Body"><A NAME="pgfId-1087476"></A>You do not need the <EM CLASS="CODE">-J</EM> run-time flag to run the compiled <EM CLASS="CODE">Myapp</EM> program; just type the following on one line: </P><PRE CLASS="CODE"><A NAME="pgfId-1087477"></A>java -Xbootclasspath:/usr/local/java/jre/lib/rt.jar:/usr/local/java/jre/lib/i18n.jar:. Myapp</PRE></DIV></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087478"></A>Class Loading</H5><P CLASS="Body"><A NAME="pgfId-1087481"></A><A NAME="marker-1087479"></A><A NAME="marker-1087480"></A>Another way to analyze <EM CLASS="CODE">CLASSPATH</EM> problems is to locate where your application is loading its classes. The <EM CLASS="CODE">verbose</EM><A NAME="marker-1087482"></A> option to the <EM CLASS="CODE">java</EM> interpreter command shows which <EM CLASS="CODE">.zip</EM> or <EM CLASS="CODE">.jar</EM> file a class comes from when it is loaded. This way, you will be able to tell if it came from the Java platform zip file or from some other application's JAR file.</P><P CLASS="Body"><A NAME="pgfId-1087483"></A>For example, an application might be using the <EM CLASS="CODE">Password</EM> class you wrote for it or it might be loading a <EM CLASS="CODE">Password</EM> class from an installed integrated development environment (IDE) tool. You should see each JAR and zip file named as in the example below:</P><PRE CLASS="CODE"><A NAME="pgfId-1087484"></A>$ java -verbose SalesReport</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087485"></A>[Opened /usr/local/java/jdk1.2/solaris/jre/lib/rt.jar in 498 ms]</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087486"></A>[Opened /usr/local/java/jdk1.2/solaris/jre/lib/i18n.jar in 60 ms]</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087487"></A>[Loaded java.lang.NoClassDefFoundError from /usr/local/java/jdk1.2/solaris/ jre/lib/rt.jar]</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087488"></A>[Loaded java.lang.Class from /usr/local/java/jdk1.2/solaris/jre/lib/rt.jar]</PRE><PRE CLASS="CODE"><A NAME="pgfId-1087489"></A>[Loaded java.lang.Object from /usr/local/java/jdk1.2/solaris/jre/lib/rt.jar]</PRE></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087490"></A>Including Debug Code</H5><P CLASS="Body"><A NAME="pgfId-1087491"></A>A common way to add diagnostic code to an application is to use <EM CLASS="CODE">System.out.println</EM> statements at strategic locations in the application. This technique is fine during development, providing you remember to remove them all when you release your product. </P><P CLASS="Body"><A NAME="pgfId-1087492"></A>However, there are other approaches that are just as simple, do not affect the performance of your application, and do not display messages that you do not want your customers to see. The following are two techniques that overcome the problems with <EM CLASS="CODE">System.out.println</EM> statements.</P></DIV><DIV><H5 CLASS="B"><A NAME="pgfId-1087493"></A>Turning Debug Information on at Run Time</H5><P CLASS="Body"><A NAME="pgfId-1087495"></A><A NAME="marker-1087494"></A>The first technique is to turn debugging information on at run time. One advantage to this is that you do not need to recompile any code if problems appear at the testing stage or on a customer site. Another advantage is that sometimes software problems can be attributed to race conditions where the same segment of code behaves unpredictably due to timing between other program interactions. </P><P CLASS="Body"><A NAME="pgfId-1087496"></A>If you control your debug code from the command line instead of adding <EM CLASS="CODE">println</EM> debug statements, you can rule out <A NAME="marker-1087497"></A>sequence problems caused by <A NAME="marker-1087498"></A>race conditions coming from the <EM CLASS="CODE">println</EM>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -