Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to generate a periodic java thread dump using JVMTI?

There are multiple ways to generate thread dumps in java.

I'd like to use JVMTI (the C API) to generate it, in order to evaluate its performance impact on a running JVM. (I am aware of jstack and JMX ; this question is not generally about getting thread dumps, but about using the JVMTI API).

I'm basing my code off of this blog post. In there, the java agent attaches to the SIGQUIT signal. I'd like to avoid that, because that is the same signal that the JVM uses in order to write a thread dump to stdout. I want to avoid that duplicity.

In other words, I'd like to either attach to a different signal, or find a way for the agent to generate a thread dump periodically.

like image 886
Ovesh Avatar asked Nov 07 '14 06:11

Ovesh


2 Answers

In there, the java agent attaches to the SIGQUIT signal. I'd like to avoid that, because that is the same signal that the JVM uses in order to write a thread dump to stdout. I want to avoid that duplicity.

Just remove the following snippet from your code

/* Set callbacks and enable event notifications */
memset(&callbacks, 0, sizeof(callbacks));
callbacks.DataDumpRequest = &dumpThreadInfo;
err = (*jvmti)->SetEventCallbacks(jvmti, &callbacks, sizeof(callbacks));
CHECK_JVMTI_ERROR(jvmti, err);
err = (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE,JVMTI_EVENT_DATA_DUMP_REQUEST, NULL);
CHECK_JVMTI_ERROR(jvmti, err);

I'd like to either attach to a different signal

Here is the paper, that is a bit old, but the information should be still relevant.

Just a sample of how to do a signal handling

import sun.misc.Signal;
import sun.misc.SignalHandler;

public class ThreadDumpSignalHandler implements SignalHandler {
    private volatile SignalHandler old;
    private ThreadDumpSignalHandler() {

    }
    public static void register(String sigName) {
        ThreadDumpSignalHandler h = new ThreadDumpSignalHandler();
        h.old = Signal.handle(new Signal(sigName), h)
    }
    public void handle(Signal sig) {
        threadDump();

        if(old != null && old != SIG_DFL && old != SIG_IGN) {
            old.handle(sig);
        }
    }
    // call your own threadDump native method.
    // note that in the implementation of this method you are able to access jvmtiEnv from *gdata (see below)
    private native void threadDump();
}

ThreadDumpSignalHandler.register("INT");

Of cause you can write completely native signal handler (please note that I haven't tested it, this is just an idea that should work)

static sighandler_t old_handler;
static void thread_dump_handler(int signum) {
    if(gdata && gdata->jvmti) {
        ... get thread dump
    }

    if(old_handler) {
        old_handler(signum);
    }
}

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved) {
    old_handler = signal(SIGINT, thread_dump_handler);

    ...
}

or find a way for the agent to generate a thread dump periodically.

In your sample there is global *gdata

typedef struct {
   /* JVMTI Environment */
   jvmtiEnv      *jvmti;
   jboolean       vm_is_started;
   /* Data access Lock */
   jrawMonitorID  lock;
} GlobalAgentData;

static GlobalAgentData *gdata;

... so, just obtain jvmtiEnv from there at any time you want (timer callbacks, etc.)

like image 147
szhem Avatar answered Nov 13 '22 17:11

szhem


If your goal is to periodically collect thread dump, you can use Java Flight Recorder, that is part of Java Mission Controller

Starting with the release of Oracle JDK 7 Update 40 (7u40), Java Mission Control is bundled with the HotSpot JVM.

like image 31
Damian Leszczyński - Vash Avatar answered Nov 13 '22 18:11

Damian Leszczyński - Vash