More‎ > ‎

How to Get Call Stack Information from Remote Java VM?

BY MARKUS SPRUNCK


This article describes how to get call stack information from a remote Java VM.

Sample Code

Within a Java application it is an easy task to access the current call stacks, but sometimes it is not possible to add code for call stack access in a application, e.g. standard software,  enterprise environments. In these cases the JDK  provides a simple interface (in tools.jar) to obtain call stack information from any running VM. 

The only limitation is, that the Java  program to be investigated runs with the same user as the calling program.  Just include the tools.jar of your JDK into the buildpath. And run the following code (don't forget to input an existing process id):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import sun.tools.attach.HotSpotVirtualMachine;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;

public class VmAccess {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("VmAccess: Error (enter process id of VM)");
        } else {
            try {
                String processId = args[0];
                System.out.println("VmAccess: start");
                VirtualMachine vm = VirtualMachine.attach(processId);    
                final HotSpotVirtualMachine hVm = (HotSpotVirtualMachine) vm;    
                final InputStream in = hVm.remoteDataDump(new Object[0]);
                final InputStreamReader inr = new InputStreamReader(in);
                final BufferedReader br = new BufferedReader(inr);
                String line = "";
                while ((line = br.readLine()) != null) {
                    System.out.println(line);
                }
                br.close();
                in.close();
                System.out.println("VmAccess: end");
            } catch (final IOException e) {
                System.out.println(e.getMessage());
            } catch (final AttachNotSupportedException e) {
                System.out.println(e.getMessage());
            }
        }
    }
}

For a running Eclipse 3.7 the program creates an output like this (abridged output):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
VmAccess: start
2012-03-19 11:41:16
Full thread dump Java HotSpot(TM) Client VM (21.0-b17 mixed mode, sharing):

"Process monitor" daemon prio=6 tid=0x069f7800 nid=0x1f98 runnable [0x3fa3f000]
   java.lang.Thread.State: RUNNABLE
	at java.lang.ProcessImpl.waitForInterruptibly(Native Method)
	at java.lang.ProcessImpl.waitFor(ProcessImpl.java:251)
	at org.eclipse.debug.core.model.RuntimeProcess$ProcessMonitorThread.run(RuntimeProcess.java:417)

"Input Stream Monitor" daemon prio=6 tid=0x069f8c00 nid=0x1e4c in Object.wait() [0x3f93f000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x0946f838> (a java.lang.Object)
	at java.lang.Object.wait(Object.java:503)
	at org.eclipse.debug.internal.core.InputStreamMonitor.writeNext(InputStreamMonitor.java:154)
	- locked <0x0946f838> (a java.lang.Object)
	at org.eclipse.debug.internal.core.InputStreamMonitor.write(InputStreamMonitor.java:124)
	at org.eclipse.debug.internal.core.InputStreamMonitor$1.run(InputStreamMonitor.java:99)
	at java.lang.Thread.run(Thread.java:722)


                    * 
                    *
                    *

"Service Thread" daemon prio=6 tid=0x02489800 nid=0x196c runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"C1 CompilerThread0" daemon prio=10 tid=0x0247c000 nid=0x1968 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Attach Listener" daemon prio=10 tid=0x0247b000 nid=0x1964 waiting on condition [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x02479c00 nid=0x1960 runnable [0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=8 tid=0x0246d000 nid=0x195c in Object.wait() [0x052cf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x12d105a8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
	- locked <0x12d105a8> (a java.lang.ref.ReferenceQueue$Lock)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
	at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

"Reference Handler" daemon prio=10 tid=0x02468400 nid=0x1958 in Object.wait() [0x051cf000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x12d10288> (a java.lang.ref.Reference$Lock)
	at java.lang.Object.wait(Object.java:503)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
	- locked <0x12d10288> (a java.lang.ref.Reference$Lock)


"VM Thread" prio=10 tid=0x02467000 nid=0x1950 runnable 

"VM Periodic Task Thread" prio=10 tid=0x024ad800 nid=0x1970 waiting on condition 

JNI global references: 645

VmAccess: end

Sponsored Link