Memory And Deadlocking Problem Analysis

Creating thread dumps to analyze deadlocking situations

If a Java application seems to deadlock, there is a simple way to analyze the current activities of all threads of a particular Java Virtual Machine. This is a so called thread dump. A thread dump will dump the state of all threads with their current call stack and all locks held by those threads. An example thread dump:

Depending on the Java Virtual Machine and operating system being used, there are several ways to generate thread dumps:

Using CRTL+BREAK in the console

Environment: Java 1.4+, Windows

Pressing this key combination in a Java console window, the Java VM creates a thread dump and issues it on the console. The Java application has to be started using java.exe instead javaw.exe on Windows. Otherwise no console window will appear at the application startup.

This way's advantage is that no additional tools are needed. Thus a thread dump is very easily realised. The downside is, that there may be other console output interfering the output.

Using the jps and jstack command line utilities

Environment: Java 5+, Linux; Java 6+, Windows

Beginning with the jdk 5, the two tools jps and jstack have been introduced. Unfortunately, the jstack command is available on Windows beginning with jdk 6, not jdk 5.

To generate a thread dump using these two tools, the following steps have to be done:

  1. Retrieve the process id using jps: The jps command will list all running Java Virtual Machines and their corresponding process id.
  2. Perform the thread dump on a particular JavaVM using jstack: After determining the process id, jstack may be called using the process id and will create a thread dump on the referenced JavaVM.

If available, the jps and jstack method is somehow more comfortable than CRTL+BREAK as calling jstack allows to redirect the output to a file without any additional overhead (like logging entries, etc.).

Example: jstack 12345 > thread-dump

Using the third party tool StackTrace

Environment: Java 1.3+

Besides the Java on board tools there is another very interesting tool for memory and deadlocking diagnosis: StackTrace of AdaptJ.

Using StackTrace, it is very comfortable to troubleshoot Java applications. StackTrace is capable to create thread dumps using an easy and straight forward UI. This is only one of the functionalities which StackTrace provides. Please see the online documentation at www.adaptj.com for further details.

Example thread dump

The following is an example thread dump being generated on a freshly started JadicePanel.

Full thread dump Java HotSpot(TM) Client VM (10.0-b19 mixed mode, sharing):

"TimerQueue" daemon prio=6 tid=0x02ea4400 nid=0x9c0 in Object.wait() [0x0393f000..0x0393fb14]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17e1c880> (a javax.swing.TimerQueue)
        at javax.swing.TimerQueue.run(Unknown Source)
        - locked <0x17e1c880> (a javax.swing.TimerQueue)
        at java.lang.Thread.run(Unknown Source)

"DestroyJavaVM" prio=6 tid=0x00295c00 nid=0xa30 waiting on condition [0x00000000..0x0090fd4c]
   java.lang.Thread.State: RUNNABLE

"AWT-EventQueue-0" prio=6 tid=0x02fc5000 nid=0xa08 in Object.wait() [0x0370f000..0x0370fb94]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17dc3470> (a java.awt.EventQueue)
        at java.lang.Object.wait(Object.java:485)
        at java.awt.EventQueue.getNextEvent(Unknown Source)
        - locked <0x17dc3470> (a java.awt.EventQueue)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
        at java.awt.EventDispatchThread.run(Unknown Source)

"AWT-Windows" daemon prio=6 tid=0x02fbfc00 nid=0x1754 runnable [0x031cf000..0x031cfc94]
   java.lang.Thread.State: RUNNABLE
        at sun.awt.windows.WToolkit.eventLoop(Native Method)
        at sun.awt.windows.WToolkit.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"AWT-Shutdown" prio=6 tid=0x02fbec00 nid=0x146c in Object.wait() [0x0317f000..0x0317fd14]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17dc3648> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:485)
        at sun.awt.AWTAutoShutdown.run(Unknown Source)
        - locked <0x17dc3648> (a java.lang.Object)
        at java.lang.Thread.run(Unknown Source)

"Java2D Disposer" daemon prio=10 tid=0x02fbe000 nid=0x10a8 in Object.wait() [0x0312f000..0x0312fd94]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17dc36d8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x17dc36d8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at sun.java2d.Disposer.run(Unknown Source)
        at java.lang.Thread.run(Unknown Source)

"Low Memory Detector" daemon prio=6 tid=0x02b26400 nid=0x12cc runnable [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x02b18400 nid=0x13a8 waiting on condition [0x00000000..0x02dcf8bc]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x02b17400 nid=0x1664 runnable [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02b16400 nid=0xc20 waiting on condition [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x02b0e400 nid=0x16b4 in Object.wait() [0x02cdf000..0x02cdfc94]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17d784e8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        - locked <0x17d784e8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(Unknown Source)
        at java.lang.ref.Finalizer$FinalizerThread.run(Unknown Source)

"Reference Handler" daemon prio=10 tid=0x02b0d400 nid=0x16bc in Object.wait() [0x02c8f000..0x02c8fd14]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0x17d78570> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:485)
        at java.lang.ref.Reference$ReferenceHandler.run(Unknown Source)
        - locked <0x17d78570> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x02b0c400 nid=0x1718 runnable

"VM Periodic Task Thread" prio=10 tid=0x02b27800 nid=0x51c waiting on condition

JNI global references: 1419

Heap
 def new generation   total 960K, used 284K [0x16960000, 0x16a60000, 0x17d10000)
  eden space 896K,  24% used [0x16960000, 0x16997110, 0x16a40000)
  from space 64K, 100% used [0x16a50000, 0x16a60000, 0x16a60000)
  to   space 64K,   0% used [0x16a40000, 0x16a40000, 0x16a50000)
 tenured generation   total 6000K, used 3654K [0x17d10000, 0x182ec000, 0x26960000)
   the space 6000K,  60% used [0x17d10000, 0x180a1a40, 0x180a1c00, 0x182ec000)
 compacting perm gen  total 12288K, used 3666K [0x26960000, 0x27560000, 0x2a960000)
   the space 12288K,  29% used [0x26960000, 0x26cf49f0, 0x26cf4a00, 0x27560000)
    ro space 8192K,  62% used [0x2a960000, 0x2ae628e8, 0x2ae62a00, 0x2b160000)
    rw space 12288K,  52% used [0x2b160000, 0x2b7a85d8, 0x2b7a8600, 0x2bd60000)