Java 以编程方式强制线程转储 - 如“jstack -F -l <PID>”
Posted
技术标签:
【中文标题】Java 以编程方式强制线程转储 - 如“jstack -F -l <PID>”【英文标题】:Java forced thread dump programmatically - like "jstack -F -l <PID>" 【发布时间】:2015-02-26 14:21:40 【问题描述】:我正在尝试以编程方式强制执行 Java 线程转储,就像命令 jstack -F -l <PID>
会执行此操作一样。
我的最佳尝试:
我从sun.jvm.hotspot.tools.JStack
创建了一个子类,覆盖run()
,其代码类似于sun.jvm.hotspot.tools.JStack.run()
,但在最后一行调用start(printstream)
而不是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);
问题:java.lang.RuntimeException: Attempt to initialize VM twice
所以我做了:
//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();
);
但这会导致:
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
我没有想法......
【问题讨论】:
【参考方案1】:我在这里找到了一些有用的东西http://crunchify.com/how-to-generate-java-thread-dump-programmatically
这可能会有所帮助,不知道PID和线程ID是否相同。
final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
final ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(<thread Ids>, 100);
【讨论】:
为什么不Thread.getAllStackTraces()? 我不知道 也不知道是否允许。 “如果有安全管理器,则使用 RuntimePermission("getStackTrace") 权限和 RuntimePermission("modifyThreadGroup") 权限调用安全管理器的 checkPermission 方法,查看是否可以获取所有线程的堆栈跟踪。 "以上是关于Java 以编程方式强制线程转储 - 如“jstack -F -l <PID>”的主要内容,如果未能解决你的问题,请参考以下文章