Java 以编程方式强制线程转储 - 如 "jstack -F -l <PID>"

标签 java unix dump programmatically-created jstack

我正在尝试以编程方式执行强制 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

我没有想法....

最佳答案

我在这里发现了一些有用的东西 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);

关于Java 以编程方式强制线程转储 - 如 "jstack -F -l <PID>",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28744850/

相关文章:

java - 寻找一个测试来重现损坏的双重检查锁定

javascript - HtmlUnit 未完全加载 YouTube 上的页面

linux - 如何从远程 SSH session 将数据发送到本地剪贴板

linux - Grep 具有一定字符数的行,包括换行符

mysql - 将数据库存储到文件中的替代方法

c - 转储内核模块堆栈

java.lang.ClassNotFoundException : javax. el.ELContext

JavaFX 加载样式表

linux - 在循环内调用 sftp 脚本时循环退出

postgresql - 将文件从 Sqlite3 转储到 PostgreSQL : why do I always get errors when import it?