2014-11-07 28 views
8

Esistono diversi modi per generare dump di thread in java.C'è un modo per generare un dump di thread java periodico usando JVMTI?

Mi piacerebbe utilizzare JVMTI (l'API C) per generarlo, al fine di valutare l'impatto delle prestazioni su una JVM in esecuzione. (Sono a conoscenza di jstack e JMX, questa domanda non riguarda generalmente l'acquisizione di dump di thread, ma l'uso dell'API JVMTI).

Sto basando il mio codice su this blog post. Lì, l'agente java si collega al segnale SIGQUIT. Vorrei evitarlo, perché quello è lo stesso segnale che la JVM usa per scrivere un dump di thread su stdout. Voglio evitare quella doppiezza.

In altre parole, mi piacerebbe collegarlo a un segnale diverso o trovare un modo per l'agente di generare periodicamente un dump di thread.

+0

Nessuno degli eventi in jvmtiEventCallbacks sembra adatto (a meno che non si desideri utilizzare DataDumpRequestion, ma se lo si è fatto, non si chiederebbe qui :)). Sembra che tu stia meglio se il tuo agente chiama direttamente "GetStackTrace". C'è una ragione per cui non puoi farlo? –

+0

@ Paul-Hicks, potresti pubblicare un link o un codice su come collegarmi al jvm in questo caso? – Ovesh

+0

Hai inserito l'agente dll o .so nel tuo jag -agentpath o lo definisci come -agentlib. Dai un'occhiata a [questa risposta] (http://stackoverflow.com/a/173447/3195526) o [Pagina di introduzione di IBM] (http://publib.boulder.ibm.com/infocenter/realtime/v2r0/index. jsp? topic =% 2Fcom.ibm.rt.doc.20% 2Fdiag% 2Ftools% 2Fjvmti.html). E 'questo quello che volevi sapere? Devo trasformare questo in una risposta? –

risposta

2

Qui l'agente java si collega al segnale SIGQUIT. Vorrei evitarlo, perché quello è lo stesso segnale che la JVM usa per scrivere un dump di thread su stdout. Voglio evitare quella doppiezza.

è sufficiente rimuovere il seguente frammento dal codice

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

mi piacerebbe o allegare a un segnale diverso

Here is la carta, che è un po 'vecchio, ma l'informazione dovrebbe essere ancora rilevante.

solo un esempio di come fare una gestione

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

Di causa è possibile scrivere gestore di segnale completamente nativa del segnale (si ricorda che non ho ancora testato, questo è solo un'idea che dovrebbe funzionare)

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

    ... 
} 

o trovare un modo per l'agente di generare periodicamente un dump thread.

Nel vostro campione c'è globale * GData

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

static GlobalAgentData *gdata; 

... così, basta ottenere jvmtiEnv da lì in qualsiasi momento si desidera (callback del timer, etc.)

+0

Ottenere '* jvmti' da' * gdata' è sicuro? Non ne sono così sicuro, ma posso provarlo. – Ovesh

+1

Dovrebbe essere sicuro. Almeno puoi sempre utilizzare [RawMonitorEnter] (https://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#RawMonitorEnter) e [RawMonitorExit] (https://docs.oracle.com). /javase/7/docs/platform/jvmti/jvmti.html#RawMonitorExit) con gdata-> lock, ma non penso che sia realmente necessario finché non si accederà a gdata-> jvmti contemporaneamente. – szhem

+1

Inoltre, è possibile creare un thread tramite [RunAgentThread] (https://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#RunAgentThread). [Start function] del thread (https://docs.oracle.com/javase/7/docs/platform/jvmti/jvmti.html#jvmtiStartFunction) accetta jvmtiEnv come suo primo parametro. In questo modo è possibile eseguire dump di thread periodici all'interno di questo thread creato in modo nativo. – szhem

-2

Nessuno degli eventi in jvmtiEventCallbacks sembrano adatti (a meno che tu non voglia usare DataDumpRequestion, ma se lo facessi, non staresti chiedendo qui: ok, quindi è più o meno come mi sono collegato alla jvm finora (con piccole differenze). Quindi immagino che questo mi porti alla prossima domanda: come ottengo un po? inter a un jvmtiEnv, per chiamare GetStackTrace, se non da un callback? Il punto è quello di chiamare t

2

Se il vostro obiettivo è quello di raccogliere periodicamente discarica filo, è possibile utilizzare Java registratore di volo, che fa parte della Java Mission Controller

A partire dalla versione di Oracle JDK 7 Aggiornamento 40 (7u40), Java Mission Control è in bundle con HotSpot JVM.

0

Il post di blog che citi ha la maggior parte di ciò che ti serve per l'impianto idraulico JVMTI. È possibile utilizzare JVMTIenv da gdata. Questo è legale. Assicurati che stai effettuando chiamate JNI per avere un JNIenv corretto per il thread corrente.

Ora è necessario aggiungere un modo per ricevere la notifica per eseguire l'azione (ad esempio: discarica del thread). Avvia un thread che ascolta su un socket, usa inotify, semafori con nome, ecc. - qualcosa che puoi attirare dall'esterno.

È quindi possibile chiamare dumpThreadInfo() dal ciclo del gestore eventi come si ritiene opportuno.