在 java 中有多种生成线程转储的方法。
我想使用JVMTI(C API)来生成它,以评估它对正在运行的 JVM 的性能影响。(我知道 jstack 和 JMX ;这个问题通常不是关于获取线程转储,而是关于使用 JVMTI API)。
我的代码基于这篇博文。在那里,java 代理附加到 SIGQUIT 信号。我想避免这种情况,因为这与 JVM 用于将线程转储写入标准输出的信号相同。我想避免这种重复。
换句话说,我想附加到不同的信号,或者想办法让代理定期生成线程转储。
在那里,java 代理附加到 SIGQUIT 信号。我想避免这种情况,因为这与 JVM 用于将线程转储写入标准输出的信号相同。我想避免这种重复。
只需从您的代码中删除以下代码段
/* 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);
我想附加到不同的信号
这是论文,有点旧,但信息应该仍然相关。
只是如何进行信号处理的示例
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(计时器回调等)
如果您的目标是定期收集线程转储,您可以使用 Java Flight Recorder,它是Java Mission Controller的一部分
从 Oracle JDK 7 Update 40 (7u40) 的发布开始,Java Mission Control 与 HotSpot JVM 捆绑在一起。
您引用的博客条目包含 JVMTI 管道所需的大部分内容。您可以使用 gdata 中的 JVMTIenv。那是合法的。确保您是否在进行 JNI 调用以使当前线程具有正确的 JNIenv。
您现在需要添加一种方法来获得通知以执行您的操作(例如:线程转储)。启动一个在套接字上侦听的线程,使用inotify,命名信号量等。 - 你可以从外面戳的东西。
然后,您可以根据需要从事件处理程序循环中调用 dumpThreadInfo()。
jvmtiEventCallbacks 中的所有事件看起来都不合适(除非你想使用 DataDumpRequestion,但如果你这样做了,你就不会在这里问了:好的,所以这就是我到目前为止附加到 jvm 的方式(略有不同) . 所以我想这让我想到了下一个问题:我如何获得一个指向 jvmtiEnv 的指针,以便调用 GetStackTrace,如果不是从回调中调用?关键是调用 t