问题
I am trying to do a forced java thread dump programmatically, just like the command jstack -F -l <PID>
would do it.
My best attempt:
I created a subclass from sun.jvm.hotspot.tools.JStack
overwriting run()
with the following code analogous to sun.jvm.hotspot.tools.JStack.run()
but in the last line calling start(printstream)
instead of start()
:
StackTrace stacktrace = new StackTrace(mixedMode, concurrentLocks);
try {
Class<?> stacktraceTool = stacktrace.getClass().getSuperclass();
Method stacktraceSetAgent = stacktraceTool.getDeclaredMethod("setAgent", new Class<?>[] { BugSpotAgent.class });
stacktraceSetAgent.setAccessible(true);
stacktraceSetAgent.invoke(stacktrace, new Object[] { this.getAgent() });
Method stacktraceSetDebugeeType = stacktraceTool.getDeclaredMethod("setDebugeeType", new Class<?>[] { int.class });
stacktraceSetDebugeeType.setAccessible(true);
stacktraceSetDebugeeType.invoke(stacktrace, new Object[] { this.getDebugeeType() });
stacktrace.run(new PrintStream(this.targetFile));
}
catch (Exception e) {
e.printStackTrace(System.err);
}
The problem: java.lang.RuntimeException: Attempt to initialize VM twice
Therefore I did:
//reset stuff
VM.shutdown();
//clear observer list
Field f = VM.class.getDeclaredField("vmInitializedObservers");
f.setAccessible(true);
VM vmm = VM.getVM();
Object fo = f.get(vmm);
List folist = (List) fo;
folist.clear();
f = sun.jvm.hotspot.runtime.Threads.class.getDeclaredField("threadFactory");
f.setAccessible(true);
f.set(null, null);
f = sun.jvm.hotspot.runtime.Threads.class.getDeclaredField("threadListField");
f.setAccessible(true);
f.setAccessible(true);
f.set(null, null);
f = sun.jvm.hotspot.runtime.Threads.class.getDeclaredField("virtualConstructor");
f.setAccessible(true);
f.set(null, null);
f = sun.jvm.hotspot.runtime.Threads.class.getDeclaredField("access");
f.setAccessible(true);
f.set(null, null);
//reinit observer list
VM.registerVMInitializedObserver(new Observer() {
public void update(Observable o, Object data) {
try {
Method initm = Threads.class.getDeclaredMethod("initialize", new Class<?>[] { TypeDataBase.class });
initm.invoke(null, new Object[] { VM.getVM().getTypeDataBase() });
}
catch (Exception e) {
e.printStackTrace();
}
}
});
But this results in:
java.lang.RuntimeException: Unable to deduce type of thread from address 0xa5d12400 (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, or SurrogateLockerThread)
at sun.jvm.hotspot.runtime.Threads.createJavaThreadWrapper(Threads.java:152)
at sun.jvm.hotspot.runtime.Threads.first(Threads.java:140)
at sun.jvm.hotspot.runtime.DeadlockDetector.createThreadTable(DeadlockDetector.java:149)
at sun.jvm.hotspot.runtime.DeadlockDetector.print(DeadlockDetector.java:56)
at sun.jvm.hotspot.runtime.DeadlockDetector.print(DeadlockDetector.java:39)
at sun.jvm.hotspot.tools.StackTrace.run(StackTrace.java:52)
at de.chili.savelogfiles.ChiliJStack.run(ChiliJStack.java:40)
at sun.jvm.hotspot.tools.Tool.start(Tool.java:221)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at de.chili.savelogfiles.JStackFRunnable.run(JStackFRunnable.java:81)
at java.lang.Thread.run(Thread.java:722)
Caused by: sun.jvm.hotspot.types.WrongTypeException: No suitable match for type of address 0xa5d12400 (nearest symbol is _ZTV10JavaThread)
at sun.jvm.hotspot.runtime.InstanceConstructor.newWrongTypeException(InstanceConstructor.java:62)
at sun.jvm.hotspot.runtime.VirtualConstructor.instantiateWrapperFor(VirtualConstructor.java:80)
at sun.jvm.hotspot.runtime.Threads.createJavaThreadWrapper(Threads.java:148)
... 13 more
sun.jvm.hotspot.utilities.AssertionFailure: Expecting GenCollectedHeap, G1CollectedHeap, or ParallelScavengeHeap, but got sun.jvm.hotspot.gc_interface.CollectedHeap
Im out of ideas....
回答1:
I found some thing useful here http://crunchify.com/how-to-generate-java-thread-dump-programmatically
May be this can help, dont know if PID and thread ids are same.
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
final ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(<thread Ids>, 100);
来源:https://stackoverflow.com/questions/28744850/java-forced-thread-dump-programmatically-like-jstack-f-l-pid