Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trigger complete stack dump programmatically?

When I send a SIGQUIT command to my java process (using kill -3 or kill -QUIT ), it prints a trace of all stacks to stderr, with information about locks held, and deadlock detection. Can I trigger this from inside the program somehow? I want to do this automatically every time a certain operation takes too long.

I know it's possible to get a stack trace (see Is there a way to dump a stack trace without throwing an exception in java?, Thread dump programmatically /JDI (Java Debugger Interface)). But I want to see the whole everything: stack traces, thread states, locks held, locks blocked on, deadlock detection, etc., i.e. everything I get when I sent a SIGQUIT; not just the stack trace.

like image 835
Dirk Groeneveld Avatar asked Oct 19 '25 20:10

Dirk Groeneveld


2 Answers

Yes you can. I've been using this code successfully to debug randomly triggered concurrency bugs:

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);
        }
    }
}

It requires Java 8 and HotSpot as the JVM as it mimics what jstack is doing, except from within the same process.

like image 166
Timo Kinnunen Avatar answered Oct 22 '25 10:10

Timo Kinnunen


I found this option

ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();

for (ThreadInfo ti : threadMxBean.dumpAllThreads(true, true)) {
    System.out.print(ti.toString());
}
like image 32
Radu Toader Avatar answered Oct 22 '25 12:10

Radu Toader



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!