JVM Troubleshooting Tools
"jinfo": Prints configuration information for a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.
"jhat" - Heap Dump Browser: Starts a Web server on a Java heap dump file (eg, produced by "jmap -dump"), allowing the heap to be browsed.
"jmap" - Memory Map: Prin00:24 10-01-2010ts shared object memory maps or heap memory details of a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.
"jsadebugd" - Serviceability Agent Debug Daemon: Attaches to a JVM process or a Java core file and acts as a debug server for remote tools to connect.
"jstack" - Stack Trace: Prints a stack trace of threads for a given JVM process or a Java core file on the local machine or on a remote machine through a debug server.
Note that not all functions described above are available on Windows systems. See next sections on how to use those tools provided in JDK 1.6 on a Windows system. 1)'jinfo' - VM Option Value Checker
The first JVM troubleshooting tool I want try is the "jinfo" tool.
The "jinfo" tool included in the Windows version of JDK 1.6 only supports functions to view and modify HotSpot VM options of the specified JVM process. Here is the "jinfo" command syntax:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jinfo
Usage: jinfo(to connect to a running process)
where is one of: -flag to print the value of the named VM option -flag [+-] to enable or disable the named VM option -flag = to set the named VM option to the given value -h -help to print this help message
HotSpot VM supports many options as described on the "Java HotSpot VM Options" page. You can change the default value of any HotSpot VM option using the "-XX:..." command option when running the "java" command.
Here is a tutorial example of how to use the "jinfo" tool get the current value of a given VM option:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\java -jar "\Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar" (Notepad started.)
(Start another command window.)C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m
424 \Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar3984 sun.tools.jps.Jps -l -m
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize 424
-XX:ThreadStackSize=0
Note that:
The "jps" tool is used to get the process ID (pid) of the Notepad JVM: 424. The output of the "jinfo" command shows that the current value of the ThreadStackSize option is 0 in the Notepad JVM.
Changing HotSpot VM Option using 'jinfo'
The "jinfo" tool can be used to view the current value of any HotSpot VM option of a given JVM process as described in the previous section.
The "jinfo" tool can also be used set a new value of any HotSpot VM option using the "jinfo -flag name=value" format. Here is
what I did to test this function with JDK 1.6 on a Windows system:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\java -XX:ThreadStackSize=512 -jar "\Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar" (Notepad started)
(Start another command window.)C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m
1424 \Program Files\java\jdk1.6.0_02\demo\jfc\Notepad\notepad.jar3124 sun.tools.jps.Jps -l -m
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize 1424
-XX:ThreadStackSize=512
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jinfo -flag ThreadStackSize=1024 1424 Exception in thread "main" java.io.IOException: Command failed in target VM at sun.tools.attach.WindowsVirtualMachine.execute (WindowsVirtualMachine.java:94) at sun.tools.attach.HotSpotVirtualMachine.executeCommand (HotSpotVirtualMachine.java:195) at sun.tools.attach.HotSpotVirtualMachine.setFlag (HotSpotVirtualMachine.java:172) at sun.tools.jinfo.JInfo.flag(JInfo.java:105) at sun.tools.jinfo.JInfo.main(JInfo.java:58)
Apparently, the target VM (the Notepad VM) does not allow me to change its option. I do not know why?
2)'jstack' - Stack Tracer of JVM Threads:
"jstack": A JVM troubleshooting tool that prints stack traces of all running threads of a given JVM process, a Java core file, or remote debug server. The "jstack" tool included in the JDK 1.6 Windows version only supports limited functions as shown the this help message:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jstack -help
Usage: jstack [-l] (to connect to running process)
Options: -l long listing. Prints additional information about locks -h or -help to print this help message
In order to test "jstack", I used this simple Java program, LongSleep.java: class LongSleep { public static void main(String[] a) { Runtime rt = Runtime.getRuntime(); System.out.println(" Free memory: " + rt.freeMemory()); System.out.println("Total memory: " + rt.totalMemory()); try {Thread.sleep(1000*60*60);} catch (InterruptedException e) {} }}
When LongSleep.java is running, I used "jps" to get its JVM process ID, pid. Then I ran "jstack" with that pid to get the following stack information:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\javac LongSleep.java
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\java LongSleep Free memory: 4997104Total memory: 5177344
(Start another command window.)C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m3296 LongSleep2224 sun.tools.jps.Jps -l -m
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jstack 3296
Full thread dump Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mod...
"Low Memory Detector" daemon prio=6 tid=0x02a7c800 nid=0xf20 runnable java.lang.Thread.State: RUNNABLE
"CompilerThread0" daemon prio=10 tid=0x02a78000 nid=0xb3c waiting ... java.lang.Thread.State: RUNNABLE
"Attach Listener" daemon prio=10 tid=0x02a76c00 nid=0x37c waiting ... java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x02a75c00 nid=0xd7c runnable java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=8 tid=0x02a71400 nid=0x2e8 in Object.wait() java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x02a6d000 nid=0xfbc in Obje... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990a38> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x22990a38> (a java.lang.ref.Reference$Lock)
"main" prio=6 tid=0x00296000 nid=0xef4 waiting on condition [0x0090... java.lang.Thread.State: TIMED_WAITING (sleeping) at java.lang.Thread.sleep(Native Method) at LongSleep.main(LongSleep.java:10)
"VM Thread" prio=10 tid=0x02a63c00 nid=0xc70 runnable
"VM Periodic Task Thread" prio=10 tid=0x02a7e000 nid=0xdd0 waiting ...
JNI global references: 571
Cool. Now I know how many threads are running inside a JVM, 8 of them. But my Java application, LongSleep, only runs under 1
thread named as "main", which is in a state called, TIMED_WAITING. This matches my expectation.
Java Thread Deadlock Demo Program:
In the previous section, "jstack" was used to print stack traces of all running threads of a given JVM process. But "jstack"
can also be used to detect deadlocks inside a given JVM process. The tutorial example below shows you how "jstack" prints
deadlock information:
1. Copy and save this Java program, import java.util.*;public class SimpleDeadLock extends Thread { public static Object l1 = new Object(); public static Object l2 = new Object(); private int index; public static void main(String[] a) { Thread t1 = new Thread1(); Thread t2 = new Thread2(); t1.start(); t2.start(); } private static class Thread1 extends Thread { public void run() { synchronized (l1) { System.out.println("Thread 1: Holding lock 1..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Thread 1: Waiting for lock 2..."); synchronized (l2) { System.out.println("Thread 2: Holding lock 1 & 2..."); } } } } private static class Thread2 extends Thread { public void run() { synchronized (l2) { System.out.println("Thread 2: Holding lock 2..."); try { Thread.sleep(10); } catch (InterruptedException e) {} System.out.println("Thread 2: Waiting for lock 1..."); synchronized (l1) { System.out.println("Thread 2: Holding lock 2 & 1..."); } } } }}
2. Compile and run SimpleDeadLock.java. A deadlock will be created immediately between two running threads:
C:\Pani>\Progra~1\java\jdk1.6.0_02\bin\javac SimpleDeadLock.java
C:\Pani>\Progra~1\java\jdk1.6.0_02\bin\java SimpleDeadLock
Thread 1: Holding lock 1...Thread 2: Holding lock 2...Thread 2: Waiting for lock 1...Thread 1: Waiting for lock 2...
This deadlock is expected - Thread 1 is holding lock 1 and waiting for lock 2, while thread 2 is holding lock 2 and waiting
for lock 1.
See the next section on how to use "jstack" to print the deadlock information and stack traces of 2 related threads.
Detecting Java Thread Deadlocks with 'jstack':
With the deadlock demo program, SimpleDeadLock.java, running in a locked status as described in the previous section, I am
ready to run "jstack" to print the deadlock information and stack traces of 2 locked threads:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m1464 SimpleDeadLock464 sun.tools.jps.Jps -l -m
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jstack 1464
Full thread dump Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mod...
"DestroyJavaVM" prio=6 tid=0x00296000 nid=0x198 waiting on conditio... java.lang.Thread.State: RUNNABLE
"Thread-1" prio=6 tid=0x02a99c00 nid=0xee0 waiting for monitor entr... java.lang.Thread.State: BLOCKED (on object monitor) at SimpleDeadLock$Thread2.run(SimpleDeadLock.java:37) - waiting to lock <0x229bd238> (a java.lang.Object) - locked <0x229bd240> (a java.lang.Object)
"Thread-0" prio=6 tid=0x02a99000 nid=0xefc waiting for monitor entr... java.lang.Thread.State: BLOCKED (on object monitor) at SimpleDeadLock$Thread1.run(SimpleDeadLock.java:24) - waiting to lock <0x229bd240> (a java.lang.Object) - locked <0x229bd238> (a java.lang.Object)
"Low Memory Detector" daemon prio=6 tid=0x02a7c800 nid=0xd2c runnab... java.lang.Thread.State: RUNNABLE
"CompilerThread0" daemon prio=10 tid=0x02a78000 nid=0x500 waiting o... java.lang.Thread.State: RUNNABLE
"Attach Listener" daemon prio=10 tid=0x02a76c00 nid=0x32c waiting o... java.lang.Thread.State: RUNNABLE
"Signal Dispatcher" daemon prio=10 tid=0x02a75c00 nid=0x190 runnabl... java.lang.Thread.State: RUNNABLE
"Finalizer" daemon prio=8 tid=0x02a6e000 nid=0xdb0 in Object.wait()... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116) - locked <0x22990b38> (a java.lang.ref.ReferenceQueue$Lock) at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132) at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x02a6d000 nid=0xa44 in Obje... java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x22990a38> (a java.lang.ref.Reference$Lock) at java.lang.Object.wait(Object.java:485) at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116) - locked <0x22990a38> (a java.lang.ref.Reference$Lock)
"VM Thread" prio=10 tid=0x02a63c00 nid=0xe88 runnable
"VM Periodic Task Thread" prio=10 tid=0x02a7e000 nid=0xf58 waiting ...
JNI global references: 571
Found one Java-level deadlock:============================="Thread-1": waiting to lock monitor 0x02a6ee64 (object 0x229bd238, a java.lang.Object), which is held by "Thread-0""Thread-0": waiting to lock monitor 0x02a6eecc (object 0x229bd240, a java.lang.Object), which is held by "Thread-1"
Java stack information for the threads listed above:==================================================="Thread-1": at SimpleDeadLock$Thread2.run(SimpleDeadLock.java:37) - waiting to lock <0x229bd238> (a java.lang.Object) - locked <0x229bd240> (a java.lang.Object)"Thread-0": at SimpleDeadLock$Thread1.run(SimpleDeadLock.java:24) - waiting to lock <0x229bd240> (a java.lang.Object) - locked <0x229bd238> (a java.lang.Object)
Found 1 deadlock.
The output of "jstack" is very useful for debugging. It tells me:
How many deadlocks exist in this JVM process. What are the 2 waiting threads for each deadlock. Stack traces of waiting threads with source code line numbers, if source codes were compile with debug options.
'jmap' - JVM Heap Dump Tool:
"jmap" - Memory Map: Prints shared object memory maps or heap memory details of a given JVM process or a Java core file on the local machine or on a remote machine through a debug server. "jmap" supports several functions with these syntaxes:
jmap [ option ] pidjmap [ option ] executable corejmap [ option ] [server-id@]remote-hostname-or-IP
When no option is used jmap prints shared object mappings. For each shared object loaded in the target VM, start address, the size of the mapping, and the full path of the shared object file are printed. This is similar to the Solaris pmap utility.
-dump:[live,]format=b,file= Dumps the Java heap in hprof binary format to filename. The live suboption is optional. If specified, only the live objects in the heap are dumped. To browse the heap dump, you can use jhat (Java Heap Analysis Tool) to read the generated file.
-finalizerinfo Prints information on objects awaiting finalization.
-heap Prints a heap summary. GC algorithm used, heap configuration and generation wise heap usage are printed.
-histo[:live] Prints a histogram of the heap. For each Java class, number of objects, memory size in bytes, and fully qualified class names are printed. VM internal class names are printed with '*' prefix. If the live suboption is specified, only live objects are counted.
-permstat Prints class loader wise statistics of permanent generation of Java heap. For each class loader, its name, liveness, address, parent class loader, and the number and size of classes it has loaded are printed. In addition, the number and size of interned Strings are printed.
-F Force. Use with jmap -dump or jmap -histo option if the pid does not respond. The live suboption is not supported in this mode.
But the "jmap" tool included in the Windows version of JDK 1.6 only supports functions to print histogram of Java object heap and generate a heap dump of a given JVM process:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jmap
Usage: jmap -histo (to print histogram of java object heap of the JVM process) jmap -dump: (to dump java heap of the JVM process)
dump-options: format=b binary default file= dump heap to
Example: jmap -dump:format=b,file=heap.bin
See the next section on how to use "jmap" to print heap histogram and to generate heap dump.
Printing Histogram of Java Object Heap:
The first function of the "jmap" tool is to print histogram of object heap of a given JVM process. Now I am going to use a sample Java program, GarbageCollection.java, I wrote in another tutorial example in this book.
The first test is to print the heap histogram of a JVM process that runs GarbageCollection.java with the "jmap -histo pid" command:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\javac GarbageCollection.java
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection
Free/total memory:23725256 2503475222710400 2503475221618728 2503475220523584 25034752...
(Start another command window.)C:\Pani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m
492 sun.tools.jps.Jps -l -m428 GarbageCollection
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jmap -histo 428
num #instances #bytes class name-------------------------------------- 1: 23 4723136 [I 2: 19 4718928 [J 3: 18 4718880 [D 4: 73925 1774200 java.lang.String 5: 208 1226400 [C 6: 28 1205064 [B 7: 18 1179936 [F 8: 68 297040 [Ljava.lang.String; 9: 332 14136 [Ljava.lang.Object; 10: 32 10240 11: 42 4032 java.lang.Class 12: 58 1392 java.util.Hashtable$Entry 13: 16 1280 [Ljava.util.HashMap$Entry; 14: 27 1000 15: 6 864 [S 16: 7 680 [Ljava.util.Hashtable$Entry; 17: 11 616 java.net.URL 18: 19 608 java.util.Locale 19: 5 560 java.lang.Thread 20: 14 560 java.util.HashMap...
The histogram gives a very good summary of heap objects used in my GarbageCollection.java program:
Most of the objects were String objects. There were 73925 of them. This matches well with what I allocated in the program:
one array of 64*64 string objects for each 1-MB object. If 16 1-MB objects were allocated, there should be 65536 string objects. "[Ljava.lang.String;" is a special class name representing a java.lang.String[] array. "[I" is a special class name representing a int[] array.
Generating Heap Dump File with 'jmap':
The second function of the "jmap" tool is to generate a heap dump of a given JVM process with the "jmap -
dump:file=" command:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\java -Xms24m -Xmx24m GarbageCollection
Free/total memory:23725256 2503475222710400 2503475221618728 2503475220523584 25034752...
Start another command window.)C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jps -l -m
764 GarbageCollection1204 sun.tools.jps.Jps -l -m
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jmap -dump:file=GarbageCollection.map 764
Dumping heap to C:\Vani\GarbageCollection.map ...Heap dump file created
C:\Vani>dir *.map
12:08 19,816,895 GarbageCollection.map
So the heap dump file, "GarbageCollection.map", is a snapshot of all heap objects used by the running GarbageCollection.java process.
Heap dump files can be browsed by the heap dump browser, "jhat", as described in the next section.
'jhat' - Java Heap Analysis Tool :
"jhat" - Java heap analysis tool or heap dump file browser: Parses a Java heap dump file and launches a Web server. "jhat" enables you to browse heap dump files using your favorite webbrowser. "jhat" supports pre-designed queries (such as 'show all instances of a known class "Foo"') as well as OQL (Object Query Language) - a SQL-like query language to query heap dumps.
Help on OQL is available from the OQL help page shown by "jhat". With the default port, OQL help is available at
http://localhost:7000/oqlhelp/
But the "jmap" tool included in the Windows version of JDK 1.6 only supports functions to print histogram of Java object heap and generate a heap dump of a given JVM process:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jhat -help
Usage: jhat [-stack ] [-refs ] [-port ] [-baseline ] [-debug ] [-version] [-h-help]
-stack false Turn off tracking object allocation call stack. -refs false Turn off tracking of references to objects -port Set the port for the HTTP server. Default is 7000. -exclude Specify a file that lists data members that should be excluded from the reachableFrom query. -baseline Specify a baseline object dump. Objects in both heap dumps with the same ID and same class will be marked as not being "new". -debug Set debug level. 0: No debug output 1: Debug hprof file parsing 2: Debug hprof file parsing, no server -version Report version number -h-help Print this help and exit The file to read
For a dump file that contains multiple heap dumps,you may specify which dump in the fileby appending "#" to the file name, i.e. "foo.hprof#3".
All boolean options default to "true"
Starting 'jhat' Web Server on a Heap Dump File:
In an earlier tutorial example, I created a Java heap dump file with the "jmap" tool on my GarbageCollection.java program.
The heap dump file is named as GarbageCollection.map. Now I want to try to run the "jhat" Web server on this dump file and browse the heap dump with a Web browser.
1. Run the "jhat" command with default options:
C:\Vani>\Progra~1\java\jdk1.6.0_02\bin\jhat GarbageCollection.map
Reading from GarbageCollection.map...Dump file created Jan 1 00:08:10 EDT 2008Snapshot read, resolving...Resolving 67324 objects...Chasing references, expect 13 dots.............Eliminating duplicate references.............Snapshot resolved.Started HTTP server on port 7000Server is ready.
2. Run a Web browser with http://localhost:7000/. The "jhat" heap dump file server page shows up:
See next sections on how to use "jhat" Web server to browse heap objects.
Listing Instance Counts of All Classes :
Running "jhat" Web server on a heap dump file offers us a very good debugging tool. You can get statistical counts of loaded classes and objects. You can review object contents and references. You can also run object queries to search for any specific information.
First, let's see how to get instance counts for all loaded classes.
1. Run a Web browser with http://localhost:7000/. The heap dump first page shows up.
2. Click the link of "Show instance counts for all classes (including platform)". The instance count page shows up:
65733 instances of class java.lang.String 362 instances of class java.lang.Class 330 instances of class [Ljava.lang.Object; 206 instances of class [C 66 instances of class [Ljava.lang.String; 58 instances of class java.util.Hashtable$Entry 50 instances of class [I 26 instances of class [B 19 instances of class java.util.Locale 19 instances of class java.util.concurrent.ConcurrentHashMap$HashEntry 17 instances of class [J 16 instances of class java.util.HashMap$Entry 16 instances of class java.util.concurrent.ConcurrentHashMap$Segment 16 instances of class java.util.concurrent.locks.ReentrantLock$NonfairSync 16 instances of class [D 16 instances of class [F 16 instances of class [Ljava.util.HashMap$Entry; 16 instances of class [Ljava.util.concurrent.ConcurrentHashMap$HashEntry; 14 instances of class java.lang.Object 14 instances of class java.util.HashMap 14 instances of class java.util.LinkedHashMap$Entry 12 instances of class java.io.ExpiringCache$Entry 11 instances of class java.net.URL 10 instances of class java.io.ObjectStreamField ....
The output shows that the highest count is the number of java.lang.String instances. This is expected, because I created String arrays with 64*64 Strings in each array.
Browsing Object Instance Values:
After looking object instance counts, I want to find some object instances created by my program and browse their values. My program, GarbageCollection.java, used the following code to create many java.lang.Object[] instances:
private static Object getOneMega() { Object[] lst = new Object[10]; lst[0] = new long[256*128]; lst[1] = new int[256*256]; lst[2] = new double[256*128]; lst[3] = new float[64*256]; lst[4] = new byte[64*1024]; String[] l = new String[64*64]; for (int i=0; i<64*64; i++) l[i] = new String("12345678"); // 16B lst[5] = l; lst[6] = new char[64*512]; return lst; } I want to find one of these Object[] instances and review its elements. 1. Run a Web browser with http://localhost:7000/. The heap dump first page shows up.
2. Click the link of "Show instance counts for all classes (including platform)". The instance count page shows up.
3. Click the link of "instances" in the line of "330 instances of class [Ljava.lang.Object;". Remember that
"[Ljava.lang.Object;" is the class name for Object[] arrays. A list of all 330 instances is displayed with their addresses.
3. Click on the first instance of "[Ljava.lang.Object;@0x25a9e6d0 (48 bytes)". The contents of this instance show up:
Object at 0x25a9e6d0
Array of 10 objects
Class:class [Ljava.lang.Object;
Values0 : [J@0x25aaea00 (262152 bytes) 1 : [I@0x25aeea10 (262152 bytes) 2 : [D@0x25b2ea20 (262152 bytes) 3 : [F@0x25b6ea30 (65544 bytes) 4 : [B@0x25b7ea40 (65544 bytes) 5 : [Ljava.lang.String;@0x25b8ea50 (16392 bytes) 6 : [C@0x25baa7b0 (65544 bytes) 7 : null8 : null9 : null
References to this object:[Ljava.lang.Object;@0x2536e920 (72 bytes) : Element 8 of [Ljava.lang.Object;@0x2536e920
Excellent! I am lucky that the first instance of Object[] is created by my code. "jhat" does a good job showing me everything about this instance. I can continue clicking its values or references to get information.
Conclusion: "jhat" is much easier to use than many Java debugger for browser heap objects.
Object Query Language (OQL):
OQL (Object Query Language): A SQL-like query language to query Java heap. OQL allows to filter/select information wanted from Java heap. While pre-defined queries such as "show all instances of class X" are already supported by HAT, OQL adds more flexibility. OQL is based on JavaScript expression language.
OQL query is of the form"
select [ from [instanceof] [ where ] ]
where class name is fully qualified Java class name (example: java.net.URL) or array class name. [C is char array name,[Ljava.io.File; is name of java.io.File[] and so on. Note that fully qualified class name does not always uniquely identify a Java class at runtime. There may be more than one Java class with the same name but loaded by different loaders. So, class name is permitted to be id string of the class object. If instanceof keyword is used, subtype objects are selected. If this keyword is not specified, only the instances of exact class specified are selected. Both from and where clauses are optional.
In select and (optional) where clauses, the expression used in JavaScript expression. Java heap objects are wrapped as convenient script objects so that fields may be accessed in natural syntax. For example, Java fields can be accessed with obj.field_name syntax and array elements can be accessed with array[index] syntax. Each Java object selected is bound to a JavaScript variable of the identifier name specified in from clause.
OQL Examples:
select all Strings of length 100 or more: select s from java.lang.String s where s.count >= 100
select all int arrays of length 256 or more: select a from [I a where a.length >= 256
show content of Strings that match a regular expression: select s.value.toString() from java.lang.String s where /java/(s.value.toString())
show path value of all File objects: select file.path.value.toString() from java.io.File file
show names of all ClassLoader classes: select classof(cl).name from instanceof java.lang.ClassLoader cl
show instances of the Class identified by given id string: select o from instanceof 0xd404b198 o
Note that 0xd404b198 is id of a Class (in a session). This is found by looking at the id shown in that class's page.
See next section on how to run OQL statements on the "jhat" Web server.
Searching for Instances with OQL Statements:
To test the power of OQL, I want to find those Object[] instances created by my program, excluding Object[] created by the JVM platform.
1. Run a Web browser with http://localhost:7000/. The heap dump first page shows up.
2. Click the link of "Execute Object Query Language (OQL) query". The OQL query page shows up.
3. Enter the following query and click the Execute button:
select i from [Ljava.lang.Object; i where i.length == 10
Cool. "jhat" returns a list of instances that matches my query condition:
But the previous OQL query is not good enough to return only Object[] instances I wanted. The query below will do a better job. Try it.
select i from [Ljava.lang.Object; i where i.length == 10 && i[5] != null && classof(i[5]).name == '[Ljava.lang.String;'
Watch out the OQL statement syntax. It takes JavaScript expressions only, not SQL expressions.
No comments:
Post a Comment