Programistyczny zrzut wątków z aplikacji Javy z wykorzystaniem protokołu JMX

Choć większość programistów Javy wie, jak stworzyć zrzut wątków z aplikacji korzystając z takich narzędzi jak jps, jconsole czy VisualVM, to w pewnych jednak okolicznościach możliwość zrobienia zrzutu pamięci programistycznie jest nieoceniona.



Pierwszym krokiem jest uzyskanie referencji na mbean ThreadMXBean.

import java.lang.management.*
import javax.management.*
import javax.management.remote.*

jmxUrl = new JMXServiceURL(serviceURL)
JMXConnector jmxc = JMXConnectorFactory.connect(jmxUrl, null)
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection()
ThreadMXBean threadMXBean  = ManagementFactory.newPlatformMXBeanProxy(mbsc,
        ManagementFactory.THREAD_MXBEAN_NAME, ThreadMXBean.class);

Wartość zmiennej serviceUrl zależy od użytego podprotokołu, ale najczęściej jest postaci service:jmx:rmi:///jndi/rmi://$HOST:$PORT/jmxrmi (JMX) lub service:jmx:jmxm://$HOST:$PORT (JMXMP).

Następnym krokiem jest uzyskanie informacji o wątkach, monitorach i synchronizatorach

ThreadInfo[] threads = threadMXBean.dumpAllThreads(true, true);

Klasa java.lang.management.ThreadInfo nadpisuje metodę toString która zwraca tekstową reprezentację stanu wątku więc może się wydawać, że wystarczy prosta iteracja po obiektach ThreadInfo

  for(t in threads) {
        println t
    }

W praktyce okazuje się, że w ten sposób uzyskamy tylko pierwszych ThreadInfo.MAX_FRAME (8) ramek stosu wywołań! Jeśli chcemy mieć cały stos wywołań, to musimy taką metodę napisać sami. Mnie osobiście bardzo odpowiada format zrzutu wątku z programu VisualVM (klasa com.sun.tools.visualvm.jmx.impl.JmxSupport)
Kompletny przykład znajduje się tutaj.
Warto tutaj wspomnieć, że narzędzie sun.tools.jstack.JStack wykorzystuje zupełnie inne podejście oparte o VirtualMachine (Attach API) – ale to już temat na inny post.

Narzędzia takie jak jstack, jps, jmap czy jinfo znajdują się w module $JAVA_HOME\lib\tools.jar i można je uruchomić jak zwykłe aplikacji Javy

# built-in thread dumper  
java -cp "%JAVA_HOME%\lib\tools.jar" sun.tools.jstack.JStack
# SA JStack
java -cp "%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\sa-jdi.jar" sun.jvm.hotspot.tools.JStack
java -cp "%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\sa-jdi.jar" sun.tools.jstack.JStack
Usage:
    jstack [-l] <pid>
        (to connect to running process)
    jstack -F [-m] [-l] <pid>
        (to connect to a hung process)
    jstack [-m] [-l] <executable> <core>
        (to connect to a core file)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (to connect to a remote debug server)

Options:
    -F  to force a thread dump. Use when jstack <pid> does not respond (process is hung)
    -m  to print both java and native frames (mixed mode)
    -l  long listing. Prints additional information about locks
    -h or -help to print this help message

lub bezpośrednio w kodzie

def env = System.getenv()
def javaHome = env['JAVA_HOME']

def jars = ['tools.jar', 'sa-jdi.jar'].collect { "$javaHome/lib/$it" as File }

def loader = this.class.classLoader.rootLoader
jars.each { loader.addURL(it.toURI().toURL()) }

sun.tools.jps.Jps.main()

Szczegóły tutaj

Skomentuj

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

Logo WordPress.com

Komentujesz korzystając z konta WordPress.com. Log Out / Zmień )

Zdjęcie z Twittera

Komentujesz korzystając z konta Twitter. Log Out / Zmień )

Facebook photo

Komentujesz korzystając z konta Facebook. Log Out / Zmień )

Google+ photo

Komentujesz korzystając z konta Google+. Log Out / Zmień )

Connecting to %s