существуетДемонстрация использования команды JVMВ этой статье демонстрируется использование некоторых команд jvm.Эта статья посвящена некоторым подробным объяснениям jstack.
эффект
jstack в основном используется для создания моментального снимка потока текущего момента виртуальной машины Java. Моментальный снимок потока — это набор стеков методов, которые выполняются каждым потоком в текущей виртуальной машине Java. Основная цель создания снимка потока — определить причину длительных пауз в потоках, таких как взаимоблокировки между потоками. , бесконечные циклы, запросы на внешние ресурсы, время ожидания и так далее. Когда поток приостановлен, вы можете просмотреть стек вызовов каждого потока через jstack и узнать, что не отвечающий поток делает в фоновом режиме или какие ресурсы он ожидает. jstack очень полезен, если запущенная в данный момент Java-программа находится в состоянии зависания.
использовать
первый взгляд на помощь
~ ᐅ 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
Объясните параметры
-F: принудительно выводит стек потока, когда на обычный запрос вывода нет ответа.
-l: В дополнение к стеку будет напечатана дополнительная информация о блокировке.При возникновении взаимоблокировки вы можете использовать jstack -l pid для наблюдения за состоянием удержания блокировки.
-m: если вызывается собственный метод, может отображаться стек C/C++.
Пример
~ ᐅ jstack -F 86200
~ ᐅ jstack -l 86200
~ ᐅ jstack -m 86200
Эффект
~ ᐅ jstack -l 86200
2018-06-27 09:06:27
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode):
"Attach Listener" #22 daemon prio=9 os_prio=31 tid=0x00007f93b9865000 nid=0xd07 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DestroyJavaVM" #21 prio=5 os_prio=31 tid=0x00007f93b996b800 nid=0x1803 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Buiest thread" #20 prio=5 os_prio=31 tid=0x00007f93b8138800 nid=0xa203 runnable [0x0000700004903000]
java.lang.Thread.State: RUNNABLE
at com.mmall.practice.example.jvm.SearchBusiestCPU$2.run(SearchBusiestCPU.java:176)
Locked ownable synchronizers:
- None
. . . Некоторые детали опущены. . .
"VM Thread" os_prio=31 tid=0x00007f93b9842000 nid=0x2d03 runnable
"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007f93b980d000 nid=0x1d07 runnable
"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007f93b980d800 nid=0x1f03 runnable
"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007f93b980e800 nid=0x2a03 runnable
"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007f93b980f000 nid=0x5403 runnable
"VM Periodic Task Thread" os_prio=31 tid=0x00007f93b8aea000 nid=0x3b03 waiting on condition
JNI global references: 62
Описание анализа
Если вы хотите анализировать потоки с помощью jstack, вы должны сначала узнать состояние потока, которое вы можете увидеть, когда команда jstack просматривает информацию о стеке потока. Первый взгляд на концепцию монитора
Монитор — это основное средство для достижения взаимного исключения и взаимодействия между потоками в Java, его можно рассматривать как объектную или классовую блокировку. Каждый объект имеет и только один монитор. На приведенной выше диаграмме описывается взаимосвязь между потоком и монитором, а также диаграмма перехода состояний потока.
Область входа (Entrt Set): указывает, что поток запрашивает блокировку объекта через синхронизацию. Если объект не заблокирован, введите владельца, в противном случае подождите в зоне входа. Как только блокировка объекта снимается другими потоками, он сразу же участвует в соревновании.
Владелец: указывает, что поток успешно конкурирует за блокировку объекта.
Область ожидания (набор ожидания): указывает, что поток снимает блокировку объекта с помощью метода ожидания объекта и ожидает пробуждения в области ожидания.
Как видно из рисунка, Монитор может принадлежать только одному потоку в определенное время.Этот поток является «Активным потоком», а другие потоки — «Ожидающими потоками», которые находятся в двух очередях «Набор записей» и «Ожидание в режиме ожидания». Состояние потока, ожидающее в «Entry Set», — «Ожидание записи монитора», а состояние потока, ожидающее в «Wait Set», — «in Object.wait()». Сначала посмотрите на потоки в «наборе входов». Мы называем участок кода, защищенный синхронизацией, критическим разделом. Когда поток подает заявку на вход в критическую секцию, он входит Очередь «Набор входа».
Состояния потоков и описания информации о стеке, выводимой командой jstack, которые заслуживают внимания, следующие:
Тупик (фокус на), тупиковый поток, как правило, относится к ситуации, когда вызовы нескольких потоков входят во взаимную оккупацию ресурсов, что приводит к ситуации, когда они не могут быть освобождены.
Runnable обычно означает, что поток находится в состоянии выполнения, поток занимает ресурсы, обрабатывает запрос, может передавать SQL в базу данных для выполнения, может работать с определенным файлом, может преобразовывать типы данных и т. д.
Ожидание условия (фокус), ожидание ресурса или ожидание выполнения условия. Конкретные причины необходимо анализировать в сочетании с фактическим стеком.
Одна ситуация заключается в том, что сеть очень загружена, почти полностью использует пропускную способность, и все еще есть много данных, ожидающих чтения и записи сетью;
Другая ситуация может заключаться в том, что сеть простаивает, но из-за таких проблем, как маршрутизация, пакеты не могут нормально поступать.
Если информация о стеке явно представляет собой код приложения, это доказывает, что поток ожидает ресурса. Как правило, когда считывается большое количество ресурсов и ресурс использует блокировку ресурса, поток переходит в состояние ожидания и ожидает чтения ресурса.
Или он ожидает выполнения других потоков и т. д.
Если обнаруживается, что большое количество потоков находится в состоянии ожидания, из стека потоков они ожидают чтения и записи в сети, что может быть признаком узкого места в сети. Поток не может быть выполнен из-за перегрузки сети.
Другая распространенная ситуация, когда возникает условие ожидания, заключается в том, что поток находится в спящем режиме и будет разбужен, когда время ожидания истечет.
Ожидание входа в монитор (фокус), ожидание входа в критическую секцию
Object.wait() или TIMED_WAITING, указывая на то, что он вызвал метод java.lang.Object.wait() после получения монитора. Каждый монитор может принадлежать только одному потоку в определенное время, который является «активным потоком», а другие потоки являются «ожидающими потоками», ожидающими в двух очередях «Entry Set» и «Wait Set» соответственно. Состояние потока, ожидающее в «Наборе записей», — «Ожидание записи монитора», а в «Ожидание». Состояние потока, ожидающего в Set, — это «in Object.wait()». Когда поток получает монитор, если он обнаруживает, что условия для продолжения выполнения потока не выполняются, он вызывает метод wait() функции объекта (обычно синхронизируемого объекта), отказались от Монитора и вошли в очередь «Ожидание установки».
На данный момент состояние потока примерно следующее:
java.lang.Thread.State: TIMED_WAITING(на мониторе объекта);
java.lang.Thread.State: WAITING(на мониторе объекта);
Заблокировано (фокус на), блокировка потока, означает, что во время выполнения текущего потока требуемые ресурсы ожидаются в течение длительного времени, но не получены, и помечаются как заблокированные диспетчером потоков контейнера, что может пониматься как поток, ожидающий тайм-аута ресурса
Демонстрация тупиковой ситуации
Сначала подготовьте код взаимоблокировки
@Slf4jpublic class DeadLock implements Runnable { public int flag = 1; //静态对象是类的所有对象共享的 private static Object o1 = new Object(), o2 = new Object(); @Override public void run() { log.info("flag:{}", flag); if (flag == 1) { synchronized (o1) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o2) { log.info("1"); } } } if (flag == 0) { synchronized (o2) { try { Thread.sleep(500); } catch (Exception e) { e.printStackTrace(); } synchronized (o1) { log.info("0"); } } } } public static void main(String[] args) { DeadLock td1 = new DeadLock(); DeadLock td2 = new DeadLock(); td1.flag = 1; td2.flag = 0; //td1,td2都处于可执行状态,但JVM线程调度先执行哪个线程是不确定的。 //td2的run()可能在td1的run()之前运行 new Thread(td1).start(); new Thread(td2).start(); }}
Результаты приведены ниже:
14:47:19.351 [Thread-1] INFO com.mmall.concurrency.example.deadLock.DeadLock - flag:0
14:47:19.351 [Thread-0] INFO com.mmall.concurrency.example.deadLock.DeadLock - flag:1
Программа печатает две строки и больше не печатает, но программа не останавливается. Это создает тупик.
Используйте команду jstack для просмотра информации о стеке
~ ᐅ jps
93893 Launcher
94055 Jps
93894 DeadLock
34413
~ ᐅ jstack -l 93894
2018-06-28 14:48:26
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode):
"Attach Listener" #13 daemon prio=9 os_prio=31 tid=0x00007ff14c101800 nid=0x1307 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"DestroyJavaVM" #12 prio=5 os_prio=31 tid=0x00007ff14c0fe000 nid=0x1703 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
Locked ownable synchronizers:
- None
"Thread-1" #11 prio=5 os_prio=31 tid=0x00007ff14ca77000 nid=0x3d03 waiting for monitor entry [0x000070000c45c000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.mmall.concurrency.example.deadLock.DeadLock.run(DeadLock.java:43)
- waiting to lock <0x000000076b5115c0> (a java.lang.Object)
- locked <0x000000076b5115d0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
"Thread-0" #10 prio=5 os_prio=31 tid=0x00007ff14ca4b000 nid=0x3c03 waiting for monitor entry [0x000070000c359000]
java.lang.Thread.State: BLOCKED (on object monitor)
at com.mmall.concurrency.example.deadLock.DeadLock.run(DeadLock.java:31)
- waiting to lock <0x000000076b5115d0> (a java.lang.Object)
- locked <0x000000076b5115c0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
. . .此处省略部分无用的thread堆栈信息。 . .
"VM Thread" os_prio=31 tid=0x00007ff14b82b000 nid=0x2d03 runnable
"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007ff14c012800 nid=0x2107 runnable
"GC task thread#1 (ParallelGC)" os_prio=31 tid=0x00007ff14c013000 nid=0x2003 runnable
"GC task thread#2 (ParallelGC)" os_prio=31 tid=0x00007ff14c816000 nid=0x2a03 runnable
"GC task thread#3 (ParallelGC)" os_prio=31 tid=0x00007ff14c816800 nid=0x5403 runnable
"VM Periodic Task Thread" os_prio=31 tid=0x00007ff14ca0b000 nid=0x3a03 waiting on condition
JNI global references: 42
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x00007ff14b0195c8 (object 0x000000076b5115c0, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x00007ff14b0174c8 (object 0x000000076b5115d0, a java.lang.Object),
which is held by "Thread-1"
Java stack information for the threads listed above:
===================================================
"Thread-1":
at com.mmall.concurrency.example.deadLock.DeadLock.run(DeadLock.java:43)
- waiting to lock <0x000000076b5115c0> (a java.lang.Object)
- locked <0x000000076b5115d0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
"Thread-0":
at com.mmall.concurrency.example.deadLock.DeadLock.run(DeadLock.java:31)
- waiting to lock <0x000000076b5115d0> (a java.lang.Object)
- locked <0x000000076b5115c0> (a java.lang.Object)
at java.lang.Thread.run(Thread.java:745)
Found 1 deadlock.
Это ясно говорит нам о том, что стек нашел один тупик на уровне Java, указав, что содержимое двух потоков вызывает тупик. Но также через информацию о стеке Java для потоков, перечисленных выше, перечислены более подробные сведения о взаимоблокировках и указано, что количество строк кода и генерировать ресурсы, чтобы конкурировать в тупиковой ситуации.
Уведомление
1. Способ создания и формат файла дампа потока для разных виртуальных машин JAVA могут различаться, разные версии JVM имеют разную информацию о дампе.
2. В реальной эксплуатации информации одного дампа часто бывает недостаточно для подтверждения проблемы. Рекомендуется формировать дамп информации 2-3 раза, если каждый дамп указывает на одну и ту же проблему, можно определить типичность проблемы.
Рекомендуем другие статьи
Подготовка и проработка параллельных вопросов в интервью
Пользовательские аннотации завершают резку базы данных
Легко поддерживается несколько источников данных
Реформирование процесса управления полномочиями на фоне операций электронной коммерции
Универсальный дизайн разрешения данных
Кратко о построении системы мониторинга и сигнализации для бизнеса с нуля
Некоторые сведения об использовании журнала для записи журналов в проектах Java
Практика Redis при расчете графика K-line с разделением времени на складе
Параллельное использование Fork/Join Framework и замечания
Параллельное программирование на Java и решения с высокой степенью параллелизма:
https://coding.imooc.com/class/195.html
Управление правами на уровне предприятия при разработке Java система:
https://coding.imooc.com/class/149.html
Если вам нравятся связанные технические статьи, не забудьте подписаться на меня~