Presentation is loading. Please wait.

Presentation is loading. Please wait.

Java Debugging & Profiling Techniques

Similar presentations

Presentation on theme: "Java Debugging & Profiling Techniques"— Presentation transcript:

1 Java Debugging & Profiling Techniques
Ethan Henry KL Group

2 Overview This session will touch on three major topics: Debugging
and Profiling plus Memory Leaks in Java

3 Debugging What’s debugging? If you don’t already know…
Debugging is the process of finding errors in your software, regardless of what kind of errors they are

4 Types of Errors Program errors can be lumped into one of three broad categories: syntactic errors static errors dynamic errors Syntactic errors are the easiest to find, dynamic errors are the most difficult

5 Syntactic Errors A syntactic error is one in which the program is ill-formed by the standard of the programming language e.g. a keyword is misspelled Syntactic errors are trivial to detect and correct the compiler does the detection for you which is one reason compiled languages are so popular

6 Static Errors Static errors are ones in which the program is syntactically correct but semantically incorrect For example, substituting a “>” for a “<” Static errors can be very difficult to detect but are usually quite obvious Java’s exception mechanism helps deal with these types of errors

7 Dynamic Errors The dynamic error is the most insidious kind of errors
Dynamic errors occur in code which is both semantically and syntactically correct but where implicit assumptions have been violated The prevention of dynamic errors is a major focus of software engineering

8 Dynamic Errors An example of a dynamic error:
the most dramatic example I could find The Ariane 5 crash on June 4, 1996 was due to a reuse error reuse of an inertial reference system software component caused a 64-bit integer to be incorrectly converted into a 16-bit unsigned integer, causing an exception that went uncaught and crashed the guidance system

9 Debugging Techniques Debugging is an art as old as programming is, so there are a lot of approaches to it For Java, we can divide debugging techniques into two categories: “Classic” Java-specific

10 Classic Debugging Techniques
print statements assert

11 Jurassic Debugging println statements
System.out.println connected to the standard output stream System.err.println connected to the standard error stream both are instances of helps with static & dynamic errors difficult to deal with in general

12 toString() The one very useful thing about using println to debug is that every object has a toString() method inherited from Java.lang.Object This means that you can always do things like this: Frame f = new Frame(“Main App”); System.out.println(“The frame info is “+f);

13 toString() By default, toString() just prints out an object identifier, so you should override it in your own classes Tip: The first thing you should do in a toString method is create a StringBuffer to hold the data you’re printing

14 Using println How can you make debugging statements easier to deal with? Conditional code via if via a pre-processor a debugging class

15 Using println If use an expression that’s constant at compile time, if statements act like conditional code and will be evaluated at compile time static final boolean DEBUG = true; // or false if(DEBUG) { System.out.println(“Some message”); }

16 Using println Another option is to use an actual pre-processor, like in C/C++ cpp, perl, m4, tcl - any general scripting language should work This is more complex, but is marginal extra work in a large project Advantage over using if: you can completely strip out the debugging code if you want

17 Using println Another technique is to use a class that logs errors
typically a singleton For example:

18 import*; public final class Log { private static Log log; private PrintStream stream; private boolean printing; private Log() { stream = System.out; printing = true; } static { log = new Log(); public static Log getLog() { return log;

19 public void setPrinting(boolean b) {
} public void setStream(OutputStream os) { if(os instanceof PrintStream) stream = (PrintStream)os; else stream = new PrintStream(os); public void println(String msg) { if(printing) stream.println(msg); public void print(String msg) { stream.print(msg);

20 Assert Assert is a classic C & C++ programming construct
Assert statements are used to verify various conditions in program code Very useful for detecting dynamic errors For example: public int doThing(int x) { Assert.assert(x > 0); // do some things... }

21 Assert While the C assert stops the program, a Java assert would be better off doing something less intrusive, like throwing a RuntimeException There is an example of a full assert package (JContracts) at: There’s a JSR on the subject as well:

22 A sample assert class public final class Assert {
// change to false if you want to disable assertions private final static boolean ENFORCE = true; public static void assert(boolean b) { if(ENFORCE && (b == false)) throw new RuntimeException("assertion violated"); }

23 Java-Specific Techniques
Exception Handling Reading Exception Messages Thread Dumps

24 Exception Handling An exception is “thrown” when some unexpected condition occurs at runtime Only instances of java.lang.Throwable (or a subclass) can be thrown by the throw statement Throwable has two subclasses: java.lang.Error java.lang.Exception

25 Errors Error objects are thrown by the virtual machine or Java library to indicate a serious problem Most applications shouldn’t try to catch or throw an Error object The predefined errors are:

26 Errors java.awt.AWTError java.lang.LinkageError
java.lang.ClassCircularityError java.lang.ClassFormatError java.lang.ExceptionInInitializerError java.lang.IncompatibleClassChangeError java.lang.AbstractMethodError java.lang.IllegalAccessError java.lang.InstantiationError java.lang.NoSuchFieldError java.lang.NoSuchMethodError java.lang.NoClassDefFoundError java.lang.UnsatisfiedLinkError java.lang.VerifyError java.lang.ThreadDeath java.lang.VirtualMachineError java.lang.InternalError java.lang.OutOfMemoryError java.lang.StackOverflowError java.lang.UnknownError

27 Exceptions An exception indicates some sort of problem that a typical application might want to deal with There are two types of exceptions: checked exceptions unchecked exceptions

28 Checked Exceptions Direct subclasses of java.lang.Exception represent exceptions that the developer must deal with These exceptions can only be thrown if declared in the throws clause of the method Any code calling a method that throws a regular exception must catch it and deal with it

29 Checked Exceptions Some examples of checked exceptions are:
java.lang.ClassNotFoundException thrown by Class.forName() thrown by many I/O operations java.lang.IllegalAccessException thrown by Class.newInstance() java.lang.InterruptedException thrown by sleep and wait

30 Unchecked Exceptions Unchecked exceptions need not be declared in the throws clause of a method and do not need to be caught These are exceptions that are too frequent to check for every time Unchecked exceptions are derived from java.lang.RuntimeException instead of java.lang.Exception RuntimeException is derived from Exception though

31 Unchecked Exceptions Some example of unchecked exceptions:
java.lang.ArithmeticException java.lang.ClassCastException java.lang.IllegalArgumentException java.lang.NumberFormatException java.lang.ArrayIndexOutOfBoundsException java.lang.StringIndexOutOfBoundsException java.lang.NegativeArraySizeException java.lang.NullPointerException

32 Handling Exceptions Exceptions are dealt with via the throw, try, catch and finally keywords The code that encounters a problem creates an exception by instantiating some exception object and throwing it throw new SomeBadException(“some message”);

33 Handling Exceptions The exception then unwinds the stack of the thread it was thrown in, looking for a try block If there is a catch associated with the try block that matches the type of the exception, the catch block is executed After the catch block executes (or if no exception was thrown) the finally block associated with the try block is executed

34 Handling Exceptions If no handler is found, the current thread’s ThreadGroup’s uncaughtException(Thread,Throwable) method is called if there is a parent ThreadGroup, pass it the exception otherwise print the exception stack trace to System.err

35 Handling Exceptions import;
public class Exception { public static void main(String args[]) { try { foo(args[0]); System.out.println("whew"); } catch(IOException e) { System.out.println("doh!"); finally { System.out.println("finally..."); System.out.println("done!");

36 Handling Exceptions public static void foo(String s) throws IOException { if(s.equals("checked")) { throw new IOException("Checked"); } else if(s.equals("unchecked")) { throw new RuntimeException("Unchecked"); System.out.println("No exception");

37 Reading Exception Messages
A typical exception stack trace looks something like this: from a modified version of the ‘Fractal’ example that comes with the JDK java.lang.NullPointerException at ContextLSystem.<init>( at CLSFractal.init( at at

38 Reading Exception Messages
Information shown: the type of exception java.lang.NullPointerException the class & method in which the exception was thrown at ContextLSystem.<init>( the full stack trace for the thread executing the code at that point at CLSFractal.init( at at Note that line numbers are not shown if a JIT is being used

39 Reading Exception Messages
There are two special methods that aren’t identified by their human-readable names: <init> a constructor <clinit> the static “class constructor” code block

40 The “Magic Thread Dump Key”
Windows: Ctrl-Break Solaris: Ctrl-\ or kill -QUIT [pid] A sample thread dump How to read a thread dump Diagnosing deadlock

41 A Sample Thread Dump From a sample application:
Full thread dump Classic VM (JDK-1.2-V, native threads): "Thread-0" (TID:0x1915a28, sys_thread_t:0x8ebd60, state:CW, native ID:0x113) prio=5 "AWT-Windows" (TID:0x1916ce0, sys_thread_t:0x8a6410, state:R, native ID:0x10a) prio=5 at Method) at at "SunToolkit.PostEventQueue-0" (TID:0x1916e10, sys_thread_t:0x8a5b70, state:CW, native ID:0x103) prio=5 at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Compiled Code) at "AWT-EventQueue-0" (TID:0x1916de0, sys_thread_t:0x8a3680, state:CW, native ID:0x10d) prio=6 at java.awt.EventQueue.getNextEvent( at "Finalizer" (TID:0x18f9320, sys_thread_t:0x8209d0, state:CW, native ID:0x116) prio=8 at java.lang.ref.ReferenceQueue.remove(Compiled Code) at java.lang.ref.Finalizer$

42 A Sample Thread Dump "Reference Handler" (TID:0x18f93b0, sys_thread_t:0x81fdc0, state:CW, native ID:0x10f) prio=10 at java.lang.Object.wait(Native Method) at java.lang.Object.wait(Compiled Code) at java.lang.ref.Reference$ "Signal dispatcher" (TID:0x18f93e0, sys_thread_t:0x81f560, state:R, native ID:0x117) prio=5 Monitor Cache Dump: <unowned> Waiting to be notified: "SunToolkit.PostEventQueue-0" (0x8a5b70) <unowned> "AWT-EventQueue-0" (0x8a3680) <unowned> "Finalizer" (0x8209d0) <unowned> "Reference Handler" (0x81fdc0)

43 A Sample Thread Dump Registered Monitor Dump:
Invoker change lock: <unowned> utf8 hash table: <unowned> JNI pinning lock: <unowned> JNI global reference lock: <unowned> BinClass lock: <unowned> Class linking lock: <unowned> System class loader lock: <unowned> Code rewrite lock: <unowned> Heap lock: <unowned> Monitor cache lock: owner "Signal dispatcher" (0x81f560) 1 entry Thread queue lock: owner "Signal dispatcher" (0x81f560) 1 entry Waiting to be notified: "Thread-0" (0x8ebd60) Monitor registry: owner "Signal dispatcher" (0x81f560) 1 entry

44 How to Read a Thread Dump
The thread dump contains the following information: a listing of all the threads running in the VM including a full stack dump if available plus the native thread id, priority and current thread state a list of all monitors that have been created including the current owner and the number of threads waiting for that monitor to be released a list of all “special” monitors these are used by the VM internally

45 Thread States Each thread has a state associated with it:
R Running or runnable thread S Suspended thread CW Thread waiting on a condition variable MW Thread waiting on a monitor lock MS Thread suspended waiting on a monitor lock You should never see a thread in the ‘MS’ state if you do, there’s a good chance it’s a VM bug

46 More on Thread Dumps The JDC has a very nice, detailed description of what each element in the thread dump is: This includes details on what each of the internal monitors are for and more It’s for JDK 1.1, but should be helpful for JDK 1.2 as well

47 Other Magic Keys Related to the “Magic Thread Dump” key is the “Magic AWT Dump” key Ctrl+Shift+F1 the code for this is hidden away inside java.awt.Window of all places Magic Netscape Console Keys hit ? in the Navigator Java console to get the list of commands

48 Interactive Debuggers
Free: jdb JBuilder Foundation (IDE) NetBeans Developer/Forte for Java (IDE) Commercial: Metamata Debug Karmira BugSeeker

49 JDK 1.0/1.1 Debugging API The Java VMs in JDK 1.0 and JDK 1.1 support a basic remote debugging API A remote agent is built into the Java VM which can be accessed over a socket via the RemoteDebugger class Most of this API has never been formally published

50 Instance of RemoteDebugger
JDK 1.0/1.1 Debugging API The basic debugger architecture: h Java Interpreter Java VM Agent Request Reply Instance of RemoteDebugger Java Debugging Client

51 JDK 1.0/1.1 Debugging API To use the debugging agent, start the JVM with the -debug command line option this may require the use of java_g On the debug client side, create an instance of the RemoteDebugger class which can be used to: list all classes in the target JVM obtain a specific RemoteClass monitor memory usage and initiate GC

52 JDK 1.0/1.1 Debugging API The RemoteClass class can be used to:
get all the fields & methods in the class set breakpoints in methods All of these classes are in the package source for this package is not included with the JDK although it is included with the VM source

53 JDK 1.0/1.1 Debugging API The classes in are:
RemoteValue RemoteBoolean RemoteByte RemoteChar RemoteDouble RemoteFloat RemoteInt RemoteLong RemoteShort RemoteObject RemoteArray RemoteClass RemoteString RemoteThread RemoteThreadGroup RemoteField RemoteStackVariable RemoteDebugger DebuggerCallback

54 JDK 1.2 Debugging API JDK 1.2 has a new, improved debugging API that is fully documented The JPDA API has been broken down into three isolated parts: JVMDI: Java Virtual Machine Debug Interface. A low-level native interface. Defines the services a VM must provide for debugging.

55 JDK 1.2 Debugging API JDWP: Java Debug Wire Protocol
Defines the format of information and requests transferred between the debugging process and the debugger front-end The transport mechanism is unspecified could be a socket, shared memory, etc JDI: Java Debug Interface A high-level 100% Pure Java interface, including support for remote debugging For use on the client/debugger side

56 communication channel
JDK 1.2 Debugging API VM back-end JVMDI debuggee communication channel JDWP front-end JDI debugger UI

57 Profiling What is Profiling? What Profiling Tells You
What Profiling Is Not Manual Profiling Profiling Techniques Overview Insertion Sampling Instrumented VM

58 What is Profiling? Profiling is measuring an application, specifically: where is the time being spent? This is “classical” profiling which method takes the most time? which method is called the most? how is memory being used? what kind of objects are being created? this in especially applicable in OO, GC’ed environments

59 What Profiling Tells You
Basic information: How much time is spent in each method? (“flat” profiling) How many objects of each type are allocated?

60 What Profiling Tells You
Beyond the basics: Program flow (“hierarchical” profiling) do calls to method A cause method B to take too much time? Per-line information which line(s) in a given method are the most expensive? Which methods created which objects? Visualization aspects Is it easy to use the profiler to get to the information you’re interested in?

61 What Profiling Is Not Profiling is measuring performance statistics on your particular application regardless of the underlying platform Benchmarking is measuring the performance of a particular platform not a specific application Optimization is an automatic technique that applies generic enhancements to speed up code regardless of the application or platform

62 Optimization Even though optimization isn’t always enough, it’s a good place to start Java is designed to be optimized by the JVM, not by the compiler even though there are optimizing compilers JIT compilers help Sun’s next-generation JVM, HotSpot, offers: generational garbage collection improved, profiling native compiler

63 Manual Profiling You don’t absolutely need to have a profiling tool to profile your code… you could build your own profiling tool see Dr. Dobb’s Journal, March 1998 Or Dr. Dobbs, Sept. 1999 use very simple code-insertion techniques System.out.println(System.getCurrentTimeMillis());

64 Profiling Techniques Overview
Commercial profilers use one of three techniques for profiling programs: insertion sampling instrumented virtual machine Why is it important to understand how a profiler works? each different technique has its own pros & cons different profilers may give different results

65 Insertion Multiple flavours: Source code insertion
profiling code goes in with the source easy to do Object code insertion profiling code goes into the .o (C++) or .class (Java) files can be done statically or dynamically hard to do modified class loader

66 Insertion Pros & Cons Insertion Pros: Insertion Cons:
can be used across a variety of platforms accurate (in some ways) can’t easily do memory profiling Insertion Cons: requires recompilation or relinking of the app profiling code may affect performance difficult to calculate exact impact

67 Sampling In sampling, the processor or VM is monitored and at regular intervals an interrupt executes and saves a “snapshot” of the processor state This data is then compared with the program’s layout in memory to get an idea of where the program was at each sample

68 Sampling Pros & Cons Sampling Pros: Sampling Cons:
no modification of app is necessary Sampling Cons: a definite time/accuracy trade-off a high sample rate is accurate, but takes a lot of time more…

69 Sampling Pros & Cons Sampling Cons:
very small methods will almost always be missed if a small method is called frequently and you have are unlucky, small but expensive methods may never show up sampling cannot easily monitor memory usage

70 Instrumented VM Another way to collect information is to instrument the Java VM Using this technique each and every VM instruction can be monitored highly accurate

71 Instrumented VM Pros&Cons
The most accurate technique Can monitor memory usage data as well as time data Can easily be extended to allow remote profiling Cons: The instrumented VM is platform-specific

72 Instrumented VMs Java 2 (JDK 1.2 and higher) Microsoft JVM
information can be accessed through JVMPI the Java Virtual Machine Profiling Interface Microsoft JVM uses a COM-based interface to provide profiling information JProbe Profiler

73 Common Bottlenecks Although profiling can yield some surprises, often the bottlenecks are fairly obvious once the profiler points them out excessive heap expansion not using System.arraycopy() using the “+” operator with String objects using unbuffered I/O streams excessive memory allocations excessive calls to slow library methods

74 Memory Leaks Java doesn’t have “memory leaks” like a C or C++ program, but… Some Java programs exhibit classic “memory leak” behavior: their memory usage grows, unbounded, over time Memory leaks usually also lead to performance problems once the process starts getting swapped out

75 What is a Memory Leak? Allocated Reachable Live exists on the heap
a path exists from some root to it Live program may use it along some future execution path

76 What is a memory leak? Memory leak in C/C++ allocated reachable
Memory leak in Java live

77 Loiterers We like to call these objects “loiterers” because:
they’re not really leaks - you can probably still release the memory somehow we don’t want to confuse Java-heap problems with native-heap problems caused by native code, which could be real memory leaks

78 Lapsed Listener Object added to collection, not removed
e.g. event listener, observer collection size can grow without bound iteration over “dead” objects degrades performance Most frequent loitering pattern Swing and AWT have had many occurs easily in any large framework C++: small loiterer or dangling pointer

79 Lingerer Reference used transiently by long-term object
Reference always reset on next use e.g. associations with menu items e.g. global action or service Not a problem in C++ benign dangling reference

80 Laggard Object changes state, some references still refer to previous state also a hard-to-find bug Common culprits changing life-cycle of class (e.g. into a singleton) constructor sets up state caches expensive-to-determine object state changes, cache not maintained C++: dangling pointer

81 Limbo Reference pinned by long-running thread Common culprits
references on stack GC doesn’t do local liveness analysis Common culprits thread stall expensive setup calls long-running analysis C++: placement of destructors

82 Loiterers For more information on causes of loiterers and how to prevent them, see the article: ‘How Do You Plug Java Memory Leaks?’ in Dr.Dobb’s, Feb. 2000 also at:

83 Memory Leaks So, how can you identify & track down memory leaks?
This is almost impossible to do without a memory analysis tool Some tools: HAT (defunct) JProbe OptimizeIt

84 Questions?

85 Fin Check out JProbe at:
Contact me at:

Download ppt "Java Debugging & Profiling Techniques"

Similar presentations

Ads by Google