3

java プロセスに SIGQUIT コマンドを送信すると ( kill -3 または kill -QUIT を使用)、すべてのスタックのトレースが stderr に出力され、保持されているロックとデッドロック検出に関する情報が出力されます。どういうわけかプログラム内からこれをトリガーできますか? 特定の操作に時間がかかりすぎるたびに、これを自動的に実行したいと考えています。

スタック トレースを取得できることはわかっています ( Is there a way to dump a stack trace without throwing an exception in java?プログラムによるスレッド ダンプ /JDI (Java Debugger Interface)を参照)。しかし、スタック トレース、スレッドの状態、保持されているロック、ブロックされているロック、デッドロックの検出など、すべてをすべて表示したいと考えています。スタックトレースだけではありません。

4

4 に答える 4

5

はい、できます。このコードを使用して、ランダムにトリガーされた同時実行のバグを正常にデバッグしています。

package utils.stack;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.lang.management.ManagementFactory;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.function.Supplier;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;

public interface DiagnosticCommand {
    String threadPrint(String... args);

    DiagnosticCommand local = ((Supplier<DiagnosticCommand>) () -> {
        try {
            MBeanServer server = ManagementFactory.getPlatformMBeanServer();
            ObjectName name = new ObjectName("com.sun.management", 
                "type", "DiagnosticCommand");
            return JMX.newMBeanProxy(server, name, DiagnosticCommand.class);
        } catch(MalformedObjectNameException e) {
            throw new AssertionError(e);
        }
    }).get();

    static void dump() {
        String print = local.threadPrint();
        Path path = Paths.get(LocalDateTime.now() + ".dump.txt");
        try {
            byte[] bytes = print.getBytes("ASCII");
            Files.write(path, bytes);
        } catch(IOException e) {
            throw new UncheckedIOException(e);
        }
    }
}

同じプロセス内を除いて、jstack が行っていることを模倣するため、JVM として Java 8 と HotSpot が必要です。

于 2015-10-21T23:42:11.507 に答える
0

完全な解決策ではありませんが、方向性を示す必要があります。

public StringBuffer getInfoXmlString() {
StringBuffer serverInfo = new StringBuffer(3000);

serverInfo.append("<ServerInfo>");
ThreadGroup rootGroup = Thread.currentThread().getThreadGroup();
ThreadGroup parent;
while ((parent = rootGroup.getParent()) != null) {
  rootGroup = parent;
}

serverInfo.append("<Threads>\r\n");
serverInfo.append(listThreads(rootGroup, "  "));
serverInfo.append("</Threads>\r\n");

serverInfo.append("</ServerInfo>\r\n");
}

private StringBuffer listThreads(ThreadGroup group, String indent) {
StringBuffer threadInfo = new StringBuffer(5000);
threadInfo.append(indent);
threadInfo.append("<ThreadGroup name=\"");
threadInfo.append(group.getName());
threadInfo.append("\" class=\"");
threadInfo.append(group.getClass().getName());
threadInfo.append("\">\r\n");

int nt = group.activeCount();
Thread[] threads = new Thread[nt * 2 + 10];
nt = group.enumerate(threads, false);

// List every thread in the group
for (int i = 0; i < nt; i++) {
  Thread t = threads[i];
  threadInfo.append(indent);
  threadInfo.append("  <Thread name=\"");
  threadInfo.append(t.getName());
  threadInfo.append("\" class=\"");
  threadInfo.append(t.getClass());
  threadInfo.append("\" alive=\"");
  threadInfo.append(t.isAlive());
  threadInfo.append("\"/>\r\n");
}
// Recursively list all subgroups
int ng = group.activeGroupCount();
ThreadGroup[] groups = new ThreadGroup[ng * 2 + 10];
ng = group.enumerate(groups, false);
for (int i = 0; i < ng; i++) {
  threadInfo.append(listThreads(groups[i], indent + "  "));
}
threadInfo.append(indent);
threadInfo.append("</ThreadGroup>\r\n");

return threadInfo;
}
于 2012-10-19T08:22:10.113 に答える