Есть ли способ сгенерировать периодический дамп потока Java с помощью JVMTI?

Существует несколько способов создания дампов потоков в java.

Я хотел бы использовать JVMTI (C API) для его создания, чтобы оценить влияние его производительности на работающую JVM. (Мне известны jstack и JMX; этот вопрос обычно не о получении дампов потоков, а об использовании JVMTI API).

Я основываю свой код на этом сообщении в блоге. Там java-агент подключается к сигналу SIGQUIT. Я бы хотел избежать этого, потому что это тот же сигнал, который использует JVM для записи дампа потока в стандартный вывод. Я хочу избежать этого двуличия.

Другими словами, я хотел бы либо подключиться к другому сигналу, либо найти способ, чтобы агент периодически генерировал дамп потока.


person Ovesh    schedule 07.11.2014    source источник
comment
Ни одно из событий в jvmtiEventCallbacks не выглядит подходящим (если вы не хотите использовать DataDumpRequestion, но если бы вы это сделали, вы бы здесь не спрашивали :)). Похоже, вам лучше, если ваш агент позвонит GetStackTrace напрямую. Есть ли причина, по которой вы не можете этого сделать?   -  person Paul Hicks    schedule 10.11.2014
comment
@ Paul-Hicks, не могли бы вы опубликовать ссылку или код о том, как я буду прикрепляться к jvm в этом случае?   -  person Ovesh    schedule 10.11.2014
comment
Вы помещаете агент dll или .so в свой jvm -agentpath или определяете его как -agentlib. Взгляните на этот ответ или вводная страница IBM. Это то, что вы хотели знать? Должен ли я превратить это в ответ?   -  person Paul Hicks    schedule 10.11.2014
comment
хорошо, так что я в значительной степени привязался к jvm до сих пор (с небольшими отличиями). Итак, я думаю, это подводит меня к следующему вопросу: как получить указатель на jvmtiEnv для вызова GetStackTrace, если не из обратного вызова? Дело в том, чтобы периодически вызывать эту функцию.   -  person Ovesh    schedule 10.11.2014


Ответы (4)


Там 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 оттуда в любое время (обратные вызовы таймера и т. д.)

person szhem    schedule 16.11.2014
comment
Безопасно ли получать *jvmti от *gdata? Я не так уверен в этом, но могу попробовать. - person Ovesh; 17.11.2014
comment
Это должно быть безопасно. По крайней мере, вы всегда можете использовать RawMonitorEnter и RawMonitorExit с gdata- ›блокировкой, но Я не думаю, что это действительно необходимо, пока вы не собираетесь одновременно обращаться к gdata- ›jvmti. - person szhem; 17.11.2014
comment
Кроме того, вы можете создать поток с помощью RunAgentThread < / а>. start функция потока принимает jvmtiEnv в качестве своей первый парам. Таким образом, вы можете делать периодические дампы потоков из этого изначально созданного потока. - person szhem; 17.11.2014
comment
использование * jvmti на 100% безопасно. Время жизни указывается до выгрузки агента. - person Trent Gray-Donald; 17.11.2014
comment
Я бы также рекомендовал не использовать сигналы - JVM сбивает с толку некоторые из них внутри, и цепочку сигналов очень сложно получить правильно. Найдите другой механизм запуска (как подсказывает мой ответ) - например: сокет, семафор и т. Д. - person Trent Gray-Donald; 17.11.2014

Если ваша цель - периодически собирать дамп потока, вы можете использовать Java Flight Recorder, который является частью Java Mission Controller

Начиная с выпуска Oracle JDK 7 Update 40 (7u40), Java Mission Control входит в состав JVM HotSpot.

person Damian Leszczyński - Vash    schedule 17.11.2014

В цитируемой вами записи в блоге есть все, что вам нужно для сантехники JVMTI. Вы можете использовать JVMTIenv из gdata. Это законно. Убедитесь, что если вы выполняете вызовы JNI, чтобы иметь правильный JNIenv для вашего текущего потока.

Теперь вам нужно добавить способ получать уведомления о ваших действиях (например, дамп потока). Создайте поток, который прослушивает сокет, использует inotify, именованные семафоры и т. Д. - то, во что можно ткнуть извне.

Затем вы можете вызвать dumpThreadInfo () из цикла обработчика событий по своему усмотрению.

person Trent Gray-Donald    schedule 17.11.2014

Ни одно из событий в jvmtiEventCallbacks не выглядит подходящим (если вы не хотите использовать DataDumpRequestion, но если бы вы это сделали, вы бы не спросили здесь: хорошо, так что это в значительной степени то, как я привязался к jvm до сих пор (с небольшими отличиями) . Итак, я думаю, это подводит меня к следующему вопросу: как мне получить указатель на jvmtiEnv, чтобы вызвать GetStackTrace, если не из обратного вызова? Дело в том, чтобы вызвать t

person sathish gurram    schedule 17.11.2014