Schedule your own Java thread dumps

So, if you ever tried to figure out what a Java program that appears to be hung is doing you are probably very familiar with the Java thread dump feature. Basically you send a signal to the JVM which responds by, essentially, writing a stack trace of each thread in the JVM to the standard output device. In fact, a thread dump contains more useful information that just a stack trace, it also show the state of each thread (i.e. runnable, waiting, etc) and which Java monitors (synchronized locks) are owned and/or being waited on.

Here is a sample snippet of a thread dump:

Full thread dump Java HotSpot(TM) Client VM (1.5.0_07-b03 mixed mode):

"Timer-5" daemon prio=10 tid=0x092d5720 nid=0x73 in Object.wait() [0x9b52f000..0x9b52fd38] 
at java.lang.Object.wait(Native Method) - waiting on <0xa2a4b978> (a java.util.TaskQueue) 
at java.util.TimerThread.mainLoop(Timer.java:509) - locked <0xa2a4b978> (a java.util.TaskQueue) 
at java.util.TimerThread.run(Timer.java:462)

"Timer-4" prio=10 tid=0x0925d418 nid=0x72 in Object.wait() [0x9b4ed000..0x9b4edab8] 
at java.lang.Object.wait(Native Method) - waiting on <0xa2a49570> (a java.util.TaskQueue) 
at java.util.TimerThread.mainLoop(Timer.java:509) - locked <0xa2a49570> (a java.util.TaskQueue) 
at java.util.TimerThread.run(Timer.java:462) 

As you can see a thread dump contains a lot of very useful information.

The method used to “request” a thread dump is to send a signal to the running JVM. In Unix this is the SIGQUIT signal which may be generated via either:

kill -3 <pid>

or

kill -QUIT <pid>

where <pid> is the process id the the JVM. You can also enter Ctrl-\ in the window where the JVM is running.

On Windows a thread dump is requested by sending a Ctrl-Break to the JVM process. This is pretty simple for foreground windows but requires a program (akin to Unix kill) to be used for JVMs running in the background (i.e. services).

The problem with requesting a thread dump is that it requires manual intervention, i.e. someone has to enter the kill command or press the Ctrl-Break keys to generate a thread dump. If you are having problems with your production site in the wee hours of the morning your support staff probably won’t appreciate getting out of bed to capture a few dumps for you. In addition, a single thread dump is not as useful as a series of dumps taken over a period of time. With a single dump you only get a snapshot of what is happening. You might see a thread holding a monitor that is causing others thread to block but you have no idea how long that condition has existed. The lock might have been released a millisecond after the dump was taken. If you have, say, 5 dumps taken over 20 minutes and the same thread is holding the monitor in all of them then you know you’ve got a problem to investigate.

The solution I’m going to propose makes use of JNI to request a thread dump of the current JVM and capture that output to a file which may be time stamped. This allows dump output to be segregated from everything else the JVM is sending to STDOUT.

Before you invest any more time in this article let me state that the solution I’m going to present here only partially works for windows. It is possible to programmatically request a thread dump under Windows but due to a limitation in Win32, the Microsoft C runtime, or both the capture to a separate file does not work. Even though Win32 provides APIs for changing the file handles used for STDOUT/STDERR, changing them after a process has started executing does not seem to make any difference. If you do all your Java work on Windows, you’ve been warned – don’t read to the end and then send me a nasty email saying I wasted your time!

Ok, the first thing we need to do is create a Java class that will serve as an interface to our native routine that captures thread dumps:

package com.utils.threaddump;

public class ThreadDumpUtil
{
public static int performThreadDump(final String fileName)
{
return(threadDumpJvm(fileName));
}

private static native int threadDumpJvm(final String fileName);

static
{
System.loadLibrary("libthreaddump");
}
}

This class loads a native library called libthreaddump when it is loaded and then exposes a static method to request a thread dump from Java code specifying the name of the file that should contain the captured dump.

Running this file through the javah tool generates a C header named com_utils_threaddump_ThreadDumpUtil.h which is used to help build our native routine.

The C code for the Unix variant follows:

#include <signal.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include "com_utils_threaddump_ThreadDumpUtil.h"

#define FILE_STDOUT             1
#define FILE_STDERR             2

JNIEXPORT jint JNICALL 
Java_com_nm_utils_threaddump_ThreadDumpUtil_threadDumpJvm(JNIEnv *env, jclass clazz, jstring fileName)
{
    /* get my process id */
    pid_t pid = getpid();
    
    /* open the file where we want the thread dump written */
    char* fName = (char*) (*env)->GetStringUTFChars(env, fileName, NULL);
    if (NULL == fName)
    {
        printf("threadDumpJvm: Out of memory converting filename");
        return((jint) -1L);
    }
    
    int fd = open(fName, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
    if (-1 == fd)
    {
        printf("threadDumpJvm: Open of file %s failed: %d[%s]\n", fName, errno, strerror(errno));
	    (*env)->ReleaseStringUTFChars(env, fileName, fName);
        return((jint) -2L);
    }
    
    /* redirect stdout and stderr to our thread dump file */
    int fdOut = dup(FILE_STDOUT);
    int fdErr = dup(FILE_STDERR);
    dup2(fd, FILE_STDOUT);
    dup2(fd, FILE_STDERR);
    close(fd);
    (*env)->ReleaseStringUTFChars(env, fileName, fName);
    
    /* send signal requesting JVM to perform a thread dump */
    kill(pid, SIGQUIT);
    
    /* this is kind of hokey but we have to wait for the dump to complete - 10 secs should be ok */
    sleep(10);
    
    /* replace the original stdout and stderr file handles */
    dup2(fdOut, FILE_STDOUT);
    dup2(fdErr, FILE_STDERR);
    return((jint) 0L);
}

Following are the compile command lines I’ve used on a couple of Unix systems to build this dynamic library:

Mac OSX:
gcc -o liblibthreaddump.dylib -dynamiclib -I. -I$JAVA_HOME/include -L/usr/lib -lc libthreaddump_unix.c

Solaris:
gcc -o liblibthreaddump.so -G -I/$JAVA_HOME/include -I/$JAVA_HOME/include/solaris libthreaddump_unix.c -lc

Here is the C code for the Windows version of the native library:

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "com_nm_utils_threaddump_ThreadDumpUtil.h"

#define FILE_STDOUT             1
#define FILE_STDERR             2

JNIEXPORT jint JNICALL 
Java_com_nm_utils_threaddump_ThreadDumpUtil_threadDumpJvm(JNIEnv *env, jclass clazz, jstring fileName)
{
	auto	HANDLE		fd;
	auto	HANDLE 		fdOut;
	auto	HANDLE		fdErr;
	auto	long		retValue = 0L;
	auto	char* 		errText = "";
	auto	DWORD 		pid = GetCurrentProcessId();
	    
    /* open the file where we want the thread dump written */
    char* fName = (char*) (*env)->GetStringUTFChars(env, fileName, NULL);
    if (NULL == fName)
    {
        printf("threadDumpJvm: Out of memory converting filename");
        return((jint) -1L);
    }
	
	fd = CreateFile((LPCTSTR) fName, GENERIC_WRITE, FILE_SHARE_WRITE, 
					NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    if (INVALID_HANDLE_VALUE == fd)
    {
        printf("threadDumpJvm: Open of file %s failed: %ld\n", fName, (long) GetLastError());
	    (*env)->ReleaseStringUTFChars(env, fileName, fName);
        return((jint) -2L);
    }

    /* redirect stdout and stderr to our thread dump file */
    fdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    fdErr = GetStdHandle(STD_ERROR_HANDLE);
    printf("fdOut=%ld fdErr=%ld\n", (long) GetStdHandle(STD_OUTPUT_HANDLE), (long) GetStdHandle(STD_ERROR_HANDLE));
    if (!SetStdHandle(STD_OUTPUT_HANDLE, fd))
    	printf("SetStdHandle failed: %ld\n", (long) GetLastError());
    	
    SetStdHandle(STD_ERROR_HANDLE, fd);
    
    printf("fdOut=%ld fdErr=%ld\n", (long) GetStdHandle(STD_OUTPUT_HANDLE), (long) GetStdHandle(STD_ERROR_HANDLE));
    if (0 == GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0))  // pid fails here????
    {
    	retValue = (long) GetLastError();
    	errText = "Generate CTRL-BREAK event failed";
   	}
	else
	{
	    /* this is kind of hokey but we have to wait for the dump to complete - 10 secs should be ok */
    	Sleep(10000L);
    }

    printf("This is a test message\n");
    
    /* replace the original stdout and stderr file handles */
    SetStdHandle(STD_OUTPUT_HANDLE, fdOut);
    SetStdHandle(STD_ERROR_HANDLE, fdErr);
	CloseHandle(fd);
    (*env)->ReleaseStringUTFChars(env, fileName, fName);
    
    if (0L != retValue)
    {
    	printf("threadDumpJvm: Error generating thread dump: %s\n", errText);
    }
        
	return((jint) retValue);
}

Remember – the file capture will not work here, it simply creates an empty file and the thread dump goes to the original STDOUT device.

Here is the command I used to create a Windows DLL using Microsoft Visual C++ 6.0:

cl -I. -I%JAVA_HOME%\include -I%JAVA_HOME%/include/win32 -LD libthreaddump_win32.c -Felibthreaddump.dll

That’s it. All the tools needed to request a thread dump any time you like. I used these tools to diagnose problems with an ATG application cluster to research problems being reported by the ATG ServerMonitor component. The ATG ServerMonitor issues warning and error log message for various reasons like the JVM being low on memory or a application request thread executing for an extended period of time. In a future post I’ll discuss how I extended the ATG ServerMonitor to capture thread dumps under these conditions.

Advertisements

24 Responses to Schedule your own Java thread dumps

  1. namsplayels says:

    Hi,

    I am new on this fantastic forum bwithers.wordpress.com
    and just want to inttoduce mygself here.

    namsplayels

    ____________________________________________
    car In That Spain Built Had EngineSports Sports Car Buick 60s During V8

  2. ClearlyPro says:

    When I tried to log on to ours dekstop, a message saying “there are not sufficient resources to load” my account with the default something-or-other came up. The message had a timer that was going to close the box, and then when it closed it would not log me on. I couldn’t turn it off normally so I cut the power. When I turned it back on I logged on fine?
    I read here Worcester PC Repair but couldnt make sense?

     

  3. […] Traces 2. JDB Example: Generating a Thread Dump 3. How to debug a multithreaded java program 4. Schedule your own Java thread dumps 5. JDK Debugging Tools 6. JDK Tools and Utilities 7. Exercise basic command line debugging tools 8. […]

  4. Hydrolyze says:

    Just wanted to say hello all. This is my first post.

    I expect to learn alot here.

  5. Cialis says:

    ej86U2 Thank you for the material. Do you mind if I posted it in her blog, of course, with reference to your site?

  6. cliewmekked says:

    Good Day i’m new here. I came upon this board I have found It positively accessible & it’s helped me a lot. I should be able to contribute and support others like its helped me.

    Thanks, See You Later.

  7. sofi says:

    Hey I am facing Thread deaths problem in my applications.
    The exact scenario is Whenever i am clicking on any link having database interactions then the server hungs and ultimately ends to Thread death.

    Also i want to mention we are using ATG 6.3.0 with ServerMonitor and DAS. It would be really great if you can help me on this

    Here is sample logs for your reference :

    **** Warning Thu Aug 18 00:05:42 PDT 2011 1313651142218 /atg/dynamo/server/ServerMonitor Request thread that has been idle for: 453.24 seconds since: Wed Aug 17 23:58:08 PDT 2011 thread=/atg/dynamo/server/DrpServer-26:ipaddr=172.16.0.234;path=/VrtAdmin/controller;sessionid=U2K2KBM1HROEHG0A0KUCFEY active=true path=/VrtAdmin/controller

    **** Warning Thu Aug 18 00:06:42 PDT 2011 1313651202209 /atg/dynamo/server/ServerMonitor Request thread that has been idle for: 513.24 seconds since: Wed Aug 17 23:58:08 PDT 2011 thread=/atg/dynamo/server/DrpServer-26:ipaddr=172.16.0.234;path=/VrtAdmin/controller;sessionid=U2K2KBM1HROEHG0A0KUCFEY active=true path=/VrtAdmin/controller

    **** Warning Thu Aug 18 00:07:42 PDT 2011 1313651262211 /atg/dynamo/server/ServerMonitor Request thread that has been idle for: 573.24 seconds since: Wed Aug 17 23:58:08 PDT 2011 thread=/atg/dynamo/server/DrpServer-26:ipaddr=172.16.0.234;path=/VrtAdmin/controller;sessionid=U2K2KBM1HROEHG0A0KUCFEY active=true path=/VrtAdmin/controller

    **** Warning Thu Aug 18 00:09:42 PDT 2011 1313651382214 /atg/dynamo/server/ServerMonitor Request thread that has been idle for: 693.24 seconds since: Wed Aug 17 23:58:08 PDT 2011 thread=/atg/dynamo/server/DrpServer-26:ipaddr=172.16.0.234;path=/VrtAdmin/controller;sessionid=U2K2KBM1HROEHG0A0KUCFEY active=true path=/VrtAdmin/controller

    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer Stopped: /atg/dynamo/server/DrpServer-26 java.lang.ThreadDeath
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at java.lang.Thread.stop(Thread.java:630)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at atg.server.tcp.RequestServerHandler.killHandler(RequestServerHandler.java:249)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at atg.server.tcp.RequestServerMonitor.performMonitorTask(RequestServerMonitor.java:741)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at atg.server.tcp.RequestServerMonitor.performScheduledTask(RequestServerMonitor.java:658)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at atg.service.scheduler.ScheduledJob.runJobs(ScheduledJob.java:435)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer at atg.service.scheduler.Scheduler$2handler.run(Scheduler.java:760)
    **** Warning Thu Aug 18 00:13:43 PDT 2011 1313651623832 /atg/dynamo/server/DrpServer

  8. JfKopfreew says:

    Катастрофа(( Свет моргнул, и компьютер больше не включается! Говорят, что там что-то сгорело… Я вообще ничего не понимаю в компьютерах, думаю, может в центр компьютерной помощи отнести, чтобы посмотрели, а по возможности и ремонт компьютеров в Пензе. Сколько эта диагностика вообще может занять?

  9. anatoliy says:

    Зарегестрироволся ошибочно. Удолите меня пожалусто!

  10. ovateeriosece says:

    скачать exit для psp, 3ds max скачать русская версия, книги microsoft скачать, sonic r скачать

  11. oceartovado says:

    Guy .. Excellent .. Amazing .. I will bookmark your blog and take the feeds alsoI’m satisfied to search out a lot of helpful info here in the publish, we want work out more strategies in this regard, thank you for sharing. . . . . .

  12. WaycleDeery says:

    Way back in 2003, before she was famous, she was just another girl on the party scene in LA, and best friends with Paris Hilton. She was dating a rapper named Ray J at the time and the two headed off for Mexico and filmed what would become one of the most downloaded videos the internet has ever seen…
    Dubbed Kim K Superstar, the 39 minute DVD was released in 2007 after Porn purveyor Vivid bought the rights and settled with Kardashian for $5 million dollars and immediately began selling the footage. The DVD sold over 1 million copies.
    Now, in a new twist, Vivid has released all of their Kim K sex tape footage… and it’s even more uncensored and longer than we imagined.
    Dubbed “Kim K Superstar, Part 2” the full online version is over 1 hour 40 minutes long.

  13. Amit says:

    Nice post. How about executing jstack through Runtime.getRuntime().exec(cmdLine); ?

  14. tovoptar says:

    Ребенок уговорил приобрести котика домой.
    В результате пришлось его дарить соседям.
    Вдруг оказалось, что у сына на кошачью шерсть аллергия!

  15. igornewok says:

    Истина проста и очевидна.
    Причем настолько очевидна, что мы, ежедневно созерцая ее,
    привычно не замечаем очевидное.
    Не верите? А мне и не нужно верить. Просто подойдите к зеркалу.
    Что вы видите?
    – Глупый вопрос, – скажете вы, – разумеется, я вижу себя.
    Вопрос совсем не глупый. Я же не спросил: “Кого вы видите?”.
    Я спросил: “Что вы видите?”
    – А что я могу увидеть, кроме себя?
    Да, вы видите себя, но разве вы не замечаете СИММЕТРИЮ?
    Два одинаковых глаза, две одинаковых щеки, два одинаковых уха…
    А под вашим симметричным лбом находятся два симметричных
    полушария вашего мозга и вы находитесь на симметричной планете,
    у которой два ПРОТИВОПОЛОЖНЫХ по своему значению полюса.
    Даже когда под своими ногами вы видите якобы не симметричный
    камень, не забывайте о том, как симметрична его кристаллическая
    решетка. Симметрия повсюду. Только слепой не увидит ее, но он
    обязательно обнаружит ее, потрогав своими симметричными руками.
    Вот почему, когда вы видите симметрию, вы видите ЗАКОНОМЕРНОСТЬ,
    а если вы видите закономерность – значит, вы видите ЗАКОН.
    – Но как я могу увидеть Закон?
    Неужели не ясно? У вас два ПРОТИВОПОЛОЖНЫХ (левый и правый)
    глаза, две противоположных руки и так далее. И вы видите, что
    ПРОТИВОПОЛОЖНОЕ ОДИНАКОВО – то есть (на языке науки)
    КАЧЕСТВЕННО СООТВЕТСТВУЕТ друг другу. Другими словами,
    когда вы видите симметрию, на самом деле вы видите
    Закон Качественного Соответствия Противоположного и за
    примерами ходить далеко не нужно – пример перед вами в зеркале.
    Мы (познавшие Истину) называем этот Закон Принципом
    Сосуществования.
    Вы спросите – Этот Закон и есть Истина?
    Отвечаю – Нет, этот Закон еще не Истина, но он является ее
    ИСТИНООБРАЗУЮЩЕЙ – неотъемлемой частью: потому что этот Закон
    также очевидно подразумевает другой.
    Я же обещал вам, что вы увидите Истину (“лучше раз увидеть,
    чем сто раз услышать”) и сдержу свое слово.
    На этот раз, предлагаю отойти от зеркала и отправиться
    (мысленно, разумеется)… в цирк! 🙂
    Почему в цирк? Потому что только там можно сегодня найти
    “живого” канатоходца, который, демонстрируя на радость публике
    свое искусство, покажет нам Истину. Я бы мог показать вам
    Истину на чем угодно, но канатоходец – самый очевидный и всем
    известный пример.
    Если вы спросите нашего воображаемого канатоходца, который
    балансирует над пропастью, что для него является ДОБРОМ, он
    обязательно ответит – РАВНОВЕСИЕ. Почему? Потому что, утратив
    равновесие, он неминуемо упадет и…
    С помощью чего канатоходец поддерживает равновесие?
    Ответ также очевиден – с помощью балансировочного шеста,
    который он держит строго посередине. Вот она “Золотая Середина”
    Гаутамы Будды, которая делит балансировочный шест на ДВЕ РАВНЫЕ
    ПОЛОВИНЫ – Качественно Соответствующие друг другу (одинаковый
    вес) ПРОТИВОПОЛОЖНОСТИ.
    Другими словами, Закон Качественного Соответствия
    Противоположного подразумевает Закон Тождества (РАВНОВЕСИЯ)
    Противоположного. Если вы увидели СОСТОЯНИЕ РАВНОВЕСИЯ, в
    котором находится канатоходец под куполом цирка, значит, вы
    увидели Закон Тождества Противоположного, а еще увидели, что
    это состояние достигается только с помощью Качественного
    Соответствия Противоположного.
    Этот Закон мы называем Принципом Существования: потому что
    все существующее ТОЖДЕСТВЕННО и, наоборот, все, что прекращает
    свое существование, ПРОТИВОРЕЧИВО.
    Так вот о чем свидетельствовала симметрия, которую вы увидели
    в зеркале! Она свидетельствовала о том, что вы существуете.
    Сомневаетесь? Если сомневаетесь, представьте что будет с вами,
    если нарушится биологическое равновесие в вашем организме, или
    представьте, что будет с Солнечной Системой, если в ней
    нарушится равновесие – тождество (противоположных) центробежных
    и центростремительных сил. Все еще сомневаетесь?
    Если же вы это представили, то увидели действие Закона Эволюции,
    ОТРИЦАЮЩЕГО НЕСООТВЕТСТВИЕ ЕГО ПРОТИВОРЕЧИЕМ (неравновесием) И
    УТВЕРЖДАЮЩЕГО СООТВЕТСТВИЕ ЕГО ТОЖДЕСТВОМ.
    А еще вы увидели Истину, которая является СУЩНОСТЬЮ всего
    существующего. Вот почему Истина пронизывает все сущее и
    кажется нам непостижимой: так как “форма богаче сущности”,
    но если не будет сущности – не будет и формы. Ничего не будет.
    Я сдержал свое слово и “показал” вам Истину.
    Разумеется, вы еще не знаете (или знаете?) как использовать
    это знание. Поэтому пример его использования вы найдете на моей
    странице (в профиле) в статье о демократии.
    Ах, да. Этот Закон (Закон Эволюции) мы называем Принципом
    Правосудия: так как Природа отрицает несоответствие его
    противоречием, а Разум судит преступника его злом.
    А еще, вы теперь знаете, что есть добро и что есть зло.

  16. mourioularp says:

    Скачать таблетку Dust: An Elysian Tail лекго и быстро тут:
    http://us.ua/1137209/

    По крайней мере для меня эта работает. С вшитыми была проблема, ничего не запускалось. А эту скачал, запустил, кнопку нажал и вуаля, все работает.

  17. treancewrenda says:

    Скачать таблетку Don’t Starve
    http://us.ua/1137209/

    Установка:
    – Скачать
    – Запустить
    – Нажать кнопку
    – Готово

  18. annyfa says:

    Всем привет! Я недавно зарегистрировалась Вконтакте, а друзей там почти нет, не с кем поболтать.
    Если кому-то тоже скучно и хочется пообщаться, добавляйтесь (особенно, если вы из Новосибирска) в друзья, будем дружить )))))
    http://vk.com/id219037808

  19. Donaldgok says:

    Вы хотите преобрести шины ради своего авто? Обратие внимание сюда:
    Для Вас низкие цены, на новые диски и бу шины у нас большой выбор.
    Рады помочь каждому.

  20. DmitriyFag says:

    Привет всем!
    Подскажите какой бы камень взять для реализации альпийской горки
    Бут и гравий пойдут для этого дела ?
    какие материалы еще могут понадобится? Альпийскую горку планирую строить сам.

  21. KennethZit says:

    дорогая, как дела? – дорогие шлюхи, а я – не имеет цены

  22. stephen says:

    http://fastthread.io/ tool is a self explanatory tool for analyzing thread dumps.

  23. Aniket Bhatnagar says:

    In 2016, why not simply use ThreadMXBean/jstack/jcmd to generate thread dumps instead of writing your own native code?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: