有没有办法使用JVMTI生成定期java线程转储?

时间:2014-11-07 06:38:09

标签: java jvmti thread-dump

在java中有多种方法可以生成线程转储。

我想使用JVMTI(C API)来生成它,以评估其对正在运行的JVM的性能影响。 (我知道jstack和JMX;这个问题一般不是关于获取线程转储,而是关于使用JVMTI API)。

我的代码基于this blog post。在那里,java代理附加到SIGQUIT信号。我想避免这种情况,因为这与JVM用于将线程转储写入stdout的信号相同。我想避免这种两面性。

换句话说,我想要附加一个不同的信号,或者为代理找到一种方法来定期生成一个线程转储。

4 个答案:

答案 0 :(得分:2)

  

在那里,java代理附加到SIGQUIT信号。我想避免这种情况,因为这与JVM用于将线程转储写入stdout的信号相同。我想避免这种两面性。

只需从代码

中删除以下代码段即可
/* 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);
  

我想要附加不同的信号

Here is论文,这有点旧,但信息应该仍然相关。

只是一个如何进行信号处理的样本

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

原因你可以写完全原生信号处理程序(请注意我还没有测试过,这只是一个应该有效的想法)

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

    ...
}
  

或找到代理定期生成线程转储的方法。

在您的示例中,有全局 * gdata

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

static GlobalAgentData *gdata;

...所以,只需在任何时候从那里获取jvmtiEnv(计时器回调等)

答案 1 :(得分:2)

如果你的目标是定期收集线程转储,你可以使用Java Flight Recorder,它是Java Mission Controller的一部分

从Oracle JDK 7 Update 40(7u40)发布开始,Java Mission Control与HotSpot JVM捆绑在一起。

答案 2 :(得分:0)

您引用的博客条目包含了JVMTI管道所需的大部分内容。您可以使用gdata中的JVMTIenv。这是合法的。确保您是否正在进行JNI调用以获得当前线程的正确JNIenv。

您现在需要添加一种方式来获取通知以采取您的操作(例如:线程转储)。旋转一个侦听套接字的线程,使用inotify,命名信号量等等。 - 你可以从外面戳一些东西。

然后,您可以根据需要从事件处理程序循环中调用dumpThreadInfo()。

答案 3 :(得分:-2)

jvmtiEventCallbacks中的所有事件看起来都不合适(除非你想使用DataDumpRequestion,但是如果你这样做了,你就不会在这里问:好吧,这几乎就是我的意思到目前为止附加到jvm(有微小的差别)。所以我想这会带我到下一个问题:如何获取指向jvmtiEnv的指针,以便调用GetStackTrace,如果不是来自回调?重点是调用吨