简体   繁体   English

有没有一种方法可以使用JVMTI生成定期的Java线程转储?

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

There are multiple ways to generate thread dumps in java. 在Java中有多种生成线程转储的方法。

I'd like to use JVMTI (the C API) to generate it, in order to evaluate its performance impact on a running JVM. 我想使用JVMTI (C API)生成它,以便评估其对运行中的JVM的性能影响。 (I am aware of jstack and JMX ; this question is not generally about getting thread dumps, but about using the JVMTI API). (我知道jstack和JMX;这个问题通常不是关于获取线程转储,而是关于使用JVMTI API)。

I'm basing my code off of this blog post . 我的代码基于此博客文章 In there, the java agent attaches to the SIGQUIT signal. 在这里,java代理附加到SIGQUIT信号。 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. 我想避免这种情况,因为这与JVM用于将线程转储写入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. 换句话说,我想附加到一个不同的信号,或者为代理找到一种定期生成线程转储的方法。

In there, the java agent attaches to the SIGQUIT signal. 在这里,java代理附加到SIGQUIT信号。 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. 我想避免这种情况,因为这与JVM用于将线程转储写入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 在您的示例中有全局* 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.) ...因此,您可以随时从那里获取jvmtiEnv(计时器回调等)。

If your goal is to periodically collect thread dump, you can use Java Flight Recorder, that is part of Java Mission Controller 如果您的目标是定期收集线程转储,则可以使用Java Flight Recorder,它是Java Mission Controller的一部分

Starting with the release of Oracle JDK 7 Update 40 (7u40), Java Mission Control is bundled with the HotSpot JVM. 从Oracle JDK 7 Update 40(7u40)发行版开始,Java Mission Control与HotSpot JVM捆绑在一起。

The blog entry you cite has most of what you need for JVMTI plumbing. 您引用的博客条目具有JVMTI管道所需的大部分功能。 You can use the JVMTIenv from gdata. 您可以从gdata使用JVMTIenv。 That is legal. 那是合法的。 Make sure if you're making JNI calls to have a proper JNIenv for your current thread. 确保是否要进行JNI调用以为当前线程使用适当的JNIenv。

You now need to add a way to get notified to take your action (eg: thread dump). 现在,您需要添加一种方法来获取通知以采取措施(例如:线程转储)。 Spin up a thread that listens on a socket, uses inotify , named semaphores, etc.. - something that you can poke from outside. 旋转一个侦听套接字,使用inotify ,名为semaphores等的线程。-您可以从外面戳一下。

You can then call dumpThreadInfo() from your event handler loop as you see fit. 然后,您可以根据需要从事件处理程序循环中调用dumpThreadInfo()。

jvmtiEventCallbacks中的所有事件都不适合(除非您想使用DataDumpRequestion,但是如果您这样做了,您将不会在这里询问:ok,所以到目前为止,这几乎就是我附加到jvm的方式(有细微差别)因此,我想这引出了下一个问题:如果不是从回调中调用GetStackTrace,如何获取指向jvmtiEnv的指针呢?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM