Что такое утилита `jstack` в Java и для чего она применяется?

Ответ

jstack — это диагностическая утилита командной строки из JDK для получения дампа потоков (thread dump) работающего процесса Java. Она показывает состояние всех потоков JVM, включая их стектрейсы и информацию о блокировках.

Основное назначение: Анализ проблем с производительностью и зависаниями:

  • Обнаружение deadlock'ов (взаимных блокировок потоков).
  • Диагностика "подвисаний" приложения (потоки в состоянии WAITING, BLOCKED).
  • Выявление высокой загрузки CPU (поиск потоков в состоянии RUNNABLE, выполняющих циклы).

Базовые команды:

# Получить PID процесса Java
jps -l
# Снять дамп потоков и сохранить в файл
jstack <pid> > thread_dump.txt
# Снять дамп с дополнительной информацией о синхронизаторах
jstack -l <pid> > thread_dump_with_locks.txt

Пример анализа deadlock в выводе jstack: Утилита явно укажет на проблему:

Found one Java-level deadlock:
=============================
"Thread-1":
  waiting to lock monitor 0x00007f... (object 0x00000000..., a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f... (object 0x00000000..., a java.lang.Object),
  which is held by "Thread-1"

Важные замечания:

  1. Для выполнения jstack требуются те же права пользователя, что и у целевого процесса Java.
  2. В современных версиях Java предпочтительнее использовать jcmd — универсальный инструмент:
    jcmd <pid> Thread.print
  3. Для полного анализа производительности jstack следует сочетать с профилировщиками (Async Profiler, VisualVM) и метриками ОС (top, pidstat).

Ответ 18+ 🔞

Слушай, а вот этот ваш jstack — это же просто палочка-выручалочка, когда приложение вдруг встаёт как вкопанное и начинает жрать процессор, как голодный студент доширак! По сути, это такая консольная штука из JDK, которая вытряхивает из работающей Java-машины дампик всех потоков (thread dump). Она тебе вывалит на экран, чем занят каждый поток: где он торчит, на каком методе завис, и за какую блокировку дерётся с соседом.

Зачем это, спросишь? Да чтобы головную боль лечить!

  • Найти deadlock'и — когда два потока друг друга ждут, как два упрямых барана, и оба нихуя не работают. Классика!
  • Понять, почему всё «подвисло» — посмотреть, какие потоки в состоянии WAITING или BLOCKED и чего они, блядь, ждут.
  • Выяснить, кто CPU жрёт — отыскать те самые прожорливые потоки в статусе RUNNABLE, которые в бесконечном цикле какую-то хуйню крутят.

Как этим пользоваться, не сломав ничего?

# Сначала узнаём PID нашего страдающего процесса
jps -l
# А потом снимаем с него дамп, как слепок с преступника, и пишем в файлик
jstack <pid> > thread_dump.txt
# Можно и с дополнениями про локсы, если подозреваешь неладное
jstack -l <pid> > thread_dump_with_locks.txt

А вот, смотри, как jstack deadlock прямо в лоб ловит — красота же!

Found one Java-level deadlock:
=============================
"Thread-1":
  ждёт, пока освободится монитор 0x00007f... (объект 0x00000000...),
  а его держит "Thread-0"
"Thread-0":
  ждёт, пока освободится монитор 0x00007f... (объект 0x00000000...),
  а его держит "Thread-1"

Ёпта, да они друг друга в петлю загнали! Прямо как в том анекдоте.

Но есть важные нюансы, блядь!

  1. Запускать jstack нужно от того же пользователя, под которым бежит сам Java-процесс, иначе получишь по рукам.
  2. Сейчас модно и правильно использовать jcmd — это такой швейцарский нож вместо кучи отдельных отвёрток:
    jcmd <pid> Thread.print
  3. Не стоит думать, что jstack — волшебная таблетка. Для полной картины его надо с профилировщиками (типа Async Profiler) скрещивать да на метрики операционки (top, pidstat) смотреть. А то так и до ебаного микросервисного колдовства недалеко.