1 Введение в дамп потоков
1.1 Что такое дамп потока
Thread Dump — очень полезный инструмент для диагностики проблем с Java-приложениями.Каждая виртуальная машина Java имеет возможность генерировать дамп состояния всех потоков в определенный момент времени., хотя дамп потока, распечатываемый каждой виртуальной машиной Java, немного отличается, ноБольшинство из них предоставляют снимок текущего активного потока и информацию о трассировке стека всех потоков Java в JVM.Информация о стеке обычно включает полное имя класса и выполняемый метод.и, если возможно, количество строк исходного кода.
1.2 Особенности дампа потоков
- Может использоваться под различными операционными системами;
- Может использоваться под различными серверами приложений Java;
- Может использоваться в производственной среде, не влияя на производительность системы;
- Возможность найти проблему прямо в строке кода приложения;
1.3 Захват дампа потока
Обычно когда сервер зависает, падает или тормозит, необходимо захватить стек потоков сервера (Thread Dump) для последующего анализа. В реальной эксплуатации информации одного дампа часто бывает недостаточно для подтверждения проблемы. Чтобы отразить динамическое изменение состояния потока,Делать дамп потока необходимо несколько раз подряд, с интервалом каждый раз 10-20 с.Дамп информации рекомендуется генерировать не менее трех раз., если каждый дамп указывает на одну и ту же проблему, мы можем определить типичность проблемы.
-
Команда ОС для получения ThreadDump
- ps –ef | grep java
- kill -3
Уведомление:
Будьте осторожны, один шаг может привести к уничтожению серверного процесса.команда kill -9 уничтожит процесс.
-
JVM поставляется с инструментами для получения стека потоков
- jps или ps –ef | grep java (чтобы получить PID)
- jstack [-l] | tee -a jstack.log (получить ThreadDump)
2 Анализ дампа потока
2.1 Информация о дампе потока
-
Информация заголовка: время, информация JVM
2011-11-02 19:05:06 Full thread dump Java HotSpot(TM) Server VM (16.3-b01 mixed mode):
-
Информационный блок Thread INFO:
1. "Timer-0" daemon prio=10 tid=0xac190c00 nid=0xaef in Object.wait() [0xae77d000] # 线程名称:Timer-0;线程类型:daemon;优先级: 10,默认是5; # JVM线程id:tid=0xac190c00,JVM内部线程的唯一标识(通过java.lang.Thread.getId()获取,通常用自增方式实现)。 # 对应系统线程id(NativeThread ID):nid=0xaef,和top命令查看的线程pid对应,不过一个是10进制,一个是16进制。(通过命令:top -H -p pid,可以查看该进程的所有线程信息) # 线程状态:in Object.wait(); # 起始栈地址:[0xae77d000],对象的内存地址,通过JVM内存查看工具,能够看出线程是在哪儿个对象上等待; 2. java.lang.Thread.State: TIMED_WAITING (on object monitor) 3. at java.lang.Object.wait(Native Method) 4. -waiting on <0xb3885f60> (a java.util.TaskQueue) # 继续wait 5. at java.util.TimerThread.mainLoop(Timer.java:509) 6. -locked <0xb3885f60> (a java.util.TaskQueue) # 已经locked 7. at java.util.TimerThread.run(Timer.java:462)
Трассировка статистики потока Java: информация в строках 2–7 выше.. Это, безусловно, самые важные данные, и трассировка стека Java предоставляет большую часть информации, позволяющей определить источник проблемы.
-
Подробное объяснение трассировки статистики потока Java:
Информация о стеке должна интерпретироваться в обратном порядке.: программа сначала выполняет строку 7, затем строку 6 и так далее.
- locked <0xb3885f60> (a java.util.ArrayList) - waiting on <0xb3885f60> (a java.util.ArrayList)
То есть объект сначала блокируется, блокирует объект 0xb3885f60, затем снимает блокировку объекта и переходит в состояние ожидания.. Почему это происходит? Взгляните на следующий пример кода Java, чтобы понять:
synchronized(obj) { ......... obj.wait(); ......... }
Как и выше, процесс выполнения потока,Сначала используйте синхронизированный, чтобы получить монитор этого объекта (соответствует заблокированному ).Когда obj.wait() выполняется, поток отказывается от права собственности на Monitor и входит в очередь ожидания (соответствует ожиданию ).
В первой строке информации о стеке дополнительно указывается состояние потока на уровне кода,Например:
java.lang.Thread.State: TIMED_WAITING (parking)
объясняется следующим образом:
|blocked| > This thread tried to enter asynchronized block, but the lock was taken by another thread. This thread isblocked until the lock gets released. |blocked (on thin lock)| > This is the same state asblocked, but the lock in question is a thin lock. |waiting| > This thread calledObject.wait() on an object. The thread will remain there until some otherthread sends a notification to that object. |sleeping| > This thread calledjava.lang.Thread.sleep(). |parked| > This thread calledjava.util.concurrent.locks.LockSupport.park(). |suspended| > The thread's execution wassuspended by java.lang.Thread.suspend() or a JVMTI agent call.
2.2 Анализ состояния потока
Состояние потока — очень важная вещь, поэтому эти состояния будут отображаться в дампе потока, анализируя эти состояния, можно получить текущий статус потока, а затем найти возможные проблемы.Состояние потока определяется в перечисляемом типе Thread.State.:
public enum State
{
/**
* Thread state for a thread which has not yet started.
*/
NEW,
/**
* Thread state for a runnable thread. A thread in the runnable
* state is executing in the Java virtual machine but it may
* be waiting for other resources from the operating system
* such as processor.
*/
RUNNABLE,
/**
* Thread state for a thread blocked waiting for a monitor lock.
* A thread in the blocked state is waiting for a monitor lock
* to enter a synchronized block/method or
* reenter a synchronized block/method after calling
* {@link Object#wait() Object.wait}.
*/
BLOCKED,
/**
* Thread state for a waiting thread.
* A thread is in the waiting state due to calling one of the
* following methods:
* <ul>
* <li>{@link Object#wait() Object.wait} with no timeout</li>
* <li>{@link #join() Thread.join} with no timeout</li>
* <li>{@link LockSupport#park() LockSupport.park}</li>
* </ul>
*
* <p>A thread in the waiting state is waiting for another thread to
* perform a particular action.
*
* For example, a thread that has called <tt>Object.wait()</tt>
* on an object is waiting for another thread to call
* <tt>Object.notify()</tt> or <tt>Object.notifyAll()</tt> on
* that object. A thread that has called <tt>Thread.join()</tt>
* is waiting for a specified thread to terminate.
*/
WAITING,
/**
* Thread state for a waiting thread with a specified waiting time.
* A thread is in the timed waiting state due to calling one of
* the following methods with a specified positive waiting time:
* <ul>
* <li>{@link #sleep Thread.sleep}</li>
* <li>{@link Object#wait(long) Object.wait} with timeout</li>
* <li>{@link #join(long) Thread.join} with timeout</li>
* <li>{@link LockSupport#parkNanos LockSupport.parkNanos}</li>
* <li>{@link LockSupport#parkUntil LockSupport.parkUntil}</li>
* </ul>
*/
TIMED_WAITING,
/**
* Thread state for a terminated thread.
* The thread has completed execution.
*/
TERMINATED;
}
-
NEW:
Каждый поток имеет соответствующий объект Thread в куче памяти.. Thread t = new Thread() Когда объект Thread только что создан в памяти кучи и метод t.start() не вызывался, поток находится в состоянии NEW.В этом состоянии поток ничем не отличается от обычного объекта Java, это просто объект в куче памяти..
-
RUNNABLE:
Это состояние указывает, что поток имеет все условия для запуска, готов для планирования операционной системой в очереди выполнения или выполняется.. Поток в этом состоянии является относительно нормальным, но если поток остается в этом состоянии в течение длительного времени, это не является нормальным, что означает, что поток выполняется в течение длительного времени (проблема с производительностью) или поток имеет вероятность того, что вы не сможете выполнять все время (есть проблема с голоданием потока).
-
BLOCKED:
Поток ожидает получения монитора (также называемого встроенной блокировкой) объекта Java, то есть поток ожидает входа в
synchronized
Защищенный метод или блок кода. Synchronized используется для обеспечения атомарности: максимум один поток может войти в критическую область в любой момент времени, а другие потоки могут только ждать в очереди. -
WAITING:
В состоянии потока ожидание возникновения события и только при выполнении определенных условий можно получить возможность выполнения. Обычно это конкретное событие генерирует другой поток. Это,Если не происходит никакого конкретного события, поток в этом состоянии ожидает и не может получить возможность выполнить. Например:
- Поток вызывает объект obj
obj.wait()
метод, если ни один поток не вызываетobj.notify
Или obj.notifyAll, тогда у потока нет возможности возобновить работу; - Если поток A вызывает
LockSupport.park()
, другие потоки не вызываютLockSupport.unpark(A)
, то у A нет возможности возобновить работу.
- Поток вызывает объект obj
-
TIMED_WAITING:
Многие связанные с потоками классы в J.U.C предоставляют ограниченные по времени и неограниченные версии API.TIMED_WAITING означает, что поток вызвал временную версию API и ожидает истечения времени.. По истечении времени ожидания поток также может возобновить работу.Если поток переходит в состояние WAITING, для возобновления работы должно произойти определенное событие, в то время как поток в состоянии TIMED_WAITING возобновит работу, если произойдет определенное событие или истечет время..
-
TERMINATED:
Поток останется в этом состоянии после того, как выполнение потока завершится, метод run завершится нормально или возникнет исключение времени выполнения и поток завершится.. В это время в потоке остался только объект Thread, что бесполезно.
2.3 Анализ критического состояния
-
Wait on condition:The thread is either sleeping or waiting to be notified by another thread.Это состояние означает, что он ожидает другого условия, чтобы проснуться, или просто вызывает sleep(n).
На данный момент состояние потока примерно следующее:
- java.lang.Thread.State: WAITING (парковка): продолжайте ждать выполнения этого условия;
- java.lang.Thread.State: TIMED_WAITING (парковка или сон): по времени, если условие не наступает, оно будет регулярно просыпаться.
-
Ожидание записи монитора и в Object.wait():The thread is waiting to get the lock for an object (some other thread may be holding the lock). This happens if two or more threads try to execute synchronized code. Note that the lock is always for an object and not for individual methods.
В многопоточной программе JAVA для достижения синхронизации между потоками мы должны говорить о мониторе.Монитор — это основное средство реализации взаимного исключения и взаимодействия между потоками в Java, его можно рассматривать как блокировку объекта или класса.. Каждый объект имеет и только один монитор. На следующем рисунке показаны отношения между потоками и Мониторами, а также диаграмма перехода состояний потоков:
Как показано на рисунке выше, каждый монитор может принадлежать только одному потоку в определенное время.Этот поток — «ActiveThread», а другие потоки — «ожидающий поток», ожидающие в двух очередях «Entry Set» и «Wait Set» соответственно.. Состояние потока, ожидающее в «Entry Set», — «Ожидание записи монитора», а состояние потока, ожидающее в «Wait Set», — «in Object.wait()».
Сначала посмотрите на нить в "Наборе входов". Мы называем участок кода, защищенный синхронизацией, критическим разделом.Когда поток подает заявку на вход в критическую секцию, он попадает в очередь «Entry Set».. Соответствующий код выглядит так:
synchronized(obj) { ......... }
На данный момент есть две возможности:
- Монитор не принадлежит другим потокам, и в наборе записей нет других ожидающих потоков. Этот поток становится владельцем монитора соответствующего класса или объекта и выполняет код критической секции.
- монитор принадлежит другому потоку,Этот поток ожидает в очереди Entry Set.
В первом случае поток будет в состоянии «Работает», а во втором случае поток DUMP появится в состоянии «ожидание записи монитора».. следующее:
"Thread-0" prio=10 tid=0x08222eb0 nid=0x9 waiting for monitor entry [0xf927b000..0xf927bdb8] at testthread.WaitThread.run(WaitThread.java:39) - waiting to lock <0xef63bf08> (a java.lang.Object) - locked <0xef63beb8> (a java.util.ArrayList) at java.lang.Thread.run(Thread.java:595)
Настройка критической секции заключается в обеспечении атомарности и целостности исполнения кода внутри нее. Но поскольку критическая секция позволяет потокам проходить только последовательно в любое время, это противоречит первоначальному замыслу нашей многопоточной программы.Если синхронизация часто используется в многопоточной программе или используется ненадлежащим образом, это приведет к ожиданию большого количества потоков на входе в критическую секцию, что приведет к значительному падению производительности системы.. Если такая ситуация обнаружена в потоке DUMP, следует пересмотреть исходный код и доработать программу.
Посмотрите еще раз ветку в "Ожидание набора". Когда поток получает Монитор и входит в критическую секцию,Если он обнаруживает, что условия для продолжения работы потока не выполняются, он вызывает метод wait() объекта (обычно синхронизируемого объекта), покидает монитор и входит в очередь «ожидание набора». Только когда другие потоки вызывают notify() или notifyAll() для объекта, потоки в очереди "Wait Set" имеют возможность конкурировать, но только один поток получает монитор объекта и возвращается в рабочее состояние.Тема в "Wait Set", в DUMP: в Object.wait(). следующее:
"Thread-1" prio=10 tid=0x08223250 nid=0xa in Object.wait() [0xef47a000..0xef47aa38] at java.lang.Object.wait(Native Method) - waiting on <0xef63beb8> (a java.util.ArrayList) at java.lang.Object.wait(Object.java:474) at testthread.MyWaitThread.run(MyWaitThread.java:40) - locked <0xef63beb8> (a java.util.ArrayList) at java.lang.Thread.run(Thread.java:595)
Подводя итог, обычно, когда ЦП очень занят, обратите внимание на поток runnable, а когда ЦП очень простаивает, обратите внимание на поток ожидания записи монитора.
-
Заблокируйте JDK 5.0
Как упоминалось выше, неправильное использование механизмов синхронизации и мониторинга может вызвать проблемы с производительностью в многопоточных программах. В JDK 5.0 представлен механизм блокировки, позволяющий разработчикам более гибко разрабатывать высокопроизводительные параллельные многопоточные программы, которые могут заменить механизмы синхронизации и мониторинга в предыдущем JDK.Однако следует отметить, что, поскольку класс Lock является обычным классом, JVM не имеет возможности узнать занятость объекта Lock, поэтому поток DUMP не будет содержать информацию о Lock., Что касается взаимоблокировок и других проблем, то их не так просто идентифицировать с синхронизированным программированием.
2.4 Примеры критических состояний
-
Показать статус ЗАБЛОКИРОВАН
package jstack; public class BlockedState { private static Object object = new Object(); public static void main(String[] args) { Runnable task = new Runnable() { @Override public void run() { synchronized (object) { long begin = System.currentTimeMillis(); long end = System.currentTimeMillis(); // 让线程运行5分钟,会一直持有object的监视器 while ((end - begin) <= 5 * 60 * 1000) { } } } }; new Thread(task, "t1").start(); new Thread(task, "t2").start(); } }
Поток, который первым получит объект, будет выполняться в течение 5 минут.В течение 5 минут монитор объекта будет все время удерживаться, и другой поток не может выполняться в состоянии BLOCKED.:
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode): "DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x1314 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "t2" prio=6 tid=0x27d7a800 nid=0x1350 waiting for monitor entry [0x2833f000] java.lang.Thread.State: BLOCKED (on object monitor) at jstack.BlockedState$1.run(BlockedState.java:17) - waiting to lock <0x1cfcdc00> (a java.lang.Object) at java.lang.Thread.run(Thread.java:662) "t1" prio=6 tid=0x27d79400 nid=0x1338 runnable [0x282ef000] java.lang.Thread.State: RUNNABLE at jstack.BlockedState$1.run(BlockedState.java:22) - locked <0x1cfcdc00> (a java.lang.Object) at java.lang.Thread.run(Thread.java:662)
Вы можете увидеть через дамп потока:Поток t2 действительно заблокирован (на мониторе объекта). ожидание входа монитора ожидание входа в синхронизированную защищенную зону.
-
Показать статус ОЖИДАНИЕ
package jstack; public class WaitingState { private static Object object = new Object(); public static void main(String[] args) { Runnable task = new Runnable() { @Override public void run() { synchronized (object) { long begin = System.currentTimeMillis(); long end = System.currentTimeMillis(); // 让线程运行5分钟,会一直持有object的监视器 while ((end - begin) <= 5 * 60 * 1000) { try { // 进入等待的同时,会进入释放监视器 object.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } }; new Thread(task, "t1").start(); new Thread(task, "t2").start(); } }
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode): "DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x1734 waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "t2" prio=6 tid=0x27d7e000 nid=0x17f4 in Object.wait() [0x2833f000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x1cfcdc00> (a java.lang.Object) at java.lang.Object.wait(Object.java:485) at jstack.WaitingState$1.run(WaitingState.java:26) - locked <0x1cfcdc00> (a java.lang.Object) at java.lang.Thread.run(Thread.java:662) "t1" prio=6 tid=0x27d7d400 nid=0x17f0 in Object.wait() [0x282ef000] java.lang.Thread.State: WAITING (on object monitor) at java.lang.Object.wait(Native Method) - waiting on <0x1cfcdc00> (a java.lang.Object) at java.lang.Object.wait(Object.java:485) at jstack.WaitingState$1.run(WaitingState.java:26) - locked <0x1cfcdc00> (a java.lang.Object) at java.lang.Thread.run(Thread.java:662)
Можно обнаружить, что и t1, и t2 находятся в состоянии ОЖИДАНИЯ (на мониторе объекта),Причина входа в состояние ожидания заключается в том, что в Object.wait() вызывается. Через очередь блокировки и условия в пакете J.U.C это тоже эффект, вы можете практиковать это самостоятельно.
-
Показать статус TIMED_WAITING
package jstack; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class TimedWaitingState { // java的显示锁,类似java对象内置的监视器 private static Lock lock = new ReentrantLock(); // 锁关联的条件队列(类似于object.wait) private static Condition condition = lock.newCondition(); public static void main(String[] args) { Runnable task = new Runnable() { @Override public void run() { // 加锁,进入临界区 lock.lock(); try { condition.await(5, TimeUnit.MINUTES); } catch (InterruptedException e) { e.printStackTrace(); } // 解锁,退出临界区 lock.unlock(); } }; new Thread(task, "t1").start(); new Thread(task, "t2").start(); } }
Full thread dump Java HotSpot(TM) Server VM (20.12-b01 mixed mode): "DestroyJavaVM" prio=6 tid=0x00856c00 nid=0x169c waiting on condition [0x00000000] java.lang.Thread.State: RUNNABLE "t2" prio=6 tid=0x27d7d800 nid=0xc30 waiting on condition [0x2833f000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x1cfce5b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2116) at jstack.TimedWaitingState$1.run(TimedWaitingState.java:28) at java.lang.Thread.run(Thread.java:662) "t1" prio=6 tid=0x280d0c00 nid=0x16e0 waiting on condition [0x282ef000] java.lang.Thread.State: TIMED_WAITING (parking) at sun.misc.Unsafe.park(Native Method) - parking to wait for <0x1cfce5b8> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject) at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:196) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2116) at jstack.TimedWaitingState$1.run(TimedWaitingState.java:28) at java.lang.Thread.run(Thread.java:662)
Вы можете видеть, что потоки t1 и t2 находятся в java.lang.Thread.State: TIMED_WAITING (парковка),Этот представитель парковки является классом инструментов под названием JUC, а не монитором по умолчанию для java..
3 Тематическое исследование
3.1 Сценарии проблем
- Высокая загрузка ЦП, высокая нагрузка, медленный отклик
- Несколько дампов во время запроса;
- Сравнивая исполняемые потоки нескольких файлов дампа, если способ выполнения сильно меняется, значит, это нормально.Если вы выполняете тот же метод, есть некоторые проблемы;
- Найдите поток, который использует больше всего ЦП
- Используйте команду:
top -H -p pid
(pid — это номер процесса тестируемой системы), найдите идентификатор потока, который вызывает высокую загрузку ЦП,Соответствует nid потока в информации о дампе потока., но один десятичный, а другой шестнадцатеричный;- В дампе потока найдите соответствующую информацию о стеке потока в соответствии с идентификатором потока, найденным командой top;
- Низкая загрузка ЦП, но медленный отклик
выгрузить,Проверьте, много ли потоков задействовано в операциях ввода-вывода, базе данных и т. д., определите причину узкого места;
- Запрос не отвечает
Сбрасывать несколько раз,Сравните, все ли исполняемые потоки выполняли один и тот же метод, если да, поздравляю, заблокировано!
3.2 Тупик
Взаимоблокировки часто проявляются в том, что программы зависают или больше не отвечают на запросы пользователей. Наблюдаемая из операционной системы загрузка ЦП соответствующим процессом равна нулю и вскоре исчезнет из вывода top или prstat.
Например, в следующем примере это более типичная тупиковая ситуация:
"Thread-1" prio=5 tid=0x00acc490 nid=0xe50 waiting for monitor entry [0x02d3f000
..0x02d3fd68]
at deadlockthreads.TestThread.run(TestThread.java:31)
- waiting to lock <0x22c19f18> (a java.lang.Object)
- locked <0x22c19f20> (a java.lang.Object)
"Thread-0" prio=5 tid=0x00accdb0 nid=0xdec waiting for monitor entry [0x02cff000
..0x02cff9e8]
at deadlockthreads.TestThread.run(TestThread.java:31)
- waiting to lock <0x22c19f20> (a java.lang.Object)
- locked <0x22c19f18> (a java.lang.Object)
Обнаружение взаимоблокировок было улучшено в JAVA 5.О взаимоблокировках на уровне Java можно напрямую сообщать в дампе потока.,Следующее:
Found one Java-level deadlock:
=============================
"Thread-1":
waiting to lock monitor 0x0003f334 (object 0x22c19f18, a java.lang.Object),
which is held by "Thread-0"
"Thread-0":
waiting to lock monitor 0x0003f314 (object 0x22c19f20, a java.lang.Object),
which is held by "Thread-1"
3.3 Горячий замок
Горячие блокировки часто являются основным фактором, приводящим к узким местам в производительности системы.Его характеристики производительности: из-за множества потоков, конкурирующих за критические секции или блокировки, может появиться:
- Частое переключение контекста потока: с точки зрения планирования потоков операционной системой, когда поток заблокирован в ожидании ресурсов, операционная система отключит его и поместит в очередь ожидания Когда поток получит ресурс, алгоритм планирования переключит поток в. поставить в очередь на выполнение.
- много системных вызовов: из-за переключения контекста потоков, конкуренции за горячие блокировки или частого входа и выхода из критических секций может быть вызвано большое количество системных вызовов.
- Большая часть накладных расходов ЦП тратится в «системном режиме».: переключение контекста потока и системные вызовы заставят ЦП работать в «системном режиме». Другими словами, хотя система занята, доля ЦП, используемая в «пользовательском режиме», невелика, и приложение не может получить достаточно ресурсов ЦП. .
- По мере увеличения числа процессоров производительность системы снижается.. Поскольку количество ЦП увеличивается, чем больше потоков выполняется одновременно, тем чаще происходит переключение контекста потока и накладные расходы ЦП системного режима, что приводит к снижению производительности.
Все приведенные выше описания относятся к характеристикам системы с плохой масштабируемостью. С точки зрения общих показателей производительности, из-за наличия горячих блокировок потоков время отклика программы будет больше, а пропускная способность снизится.
Итак, как узнать, где появляется «горячая блокировка»??
Важным методом являетсяВ сочетании с различными инструментами операционной системы для наблюдения за использованием системных ресурсов и сбора информации DUMP потоков Java, чтобы увидеть, на каких методах потоки заблокированы., понять причину и найти соответствующее решение.
4 важных потока JVM
Некоторые из наиболее важных потоков, созданных во время работы JVM, перечислены ниже:
имя темы | принадлежать | объяснять |
---|---|---|
Attach Listener | JVM |
Attach Listener Поток отвечает за получение внешних команд, выполнение команд и возврат результатов отправителю. Обычно мы будем использовать некоторые команды, чтобы попросить JVM дать нам некоторую обратную связь, например:java -version、jmap、jstack и Т. Д. Если поток не инициализирован при запуске JVM, он будет запущен, когда пользователь впервые выполнит команду JVM. |
Signal Dispatcher | JVM | упомянутый ранееAttach Listener Ответственность за поток состоит в том, чтобы получать внешние команды JVM, когда команда успешно получена, она будет передана вsignal dispather Потоки распределяются по разным модулям для обработки команд и возврата результатов обработки.signal dispather Поток также инициализируется, когда он впервые получает внешнюю команду JVM. |
CompilerThread0 | JVM | привык звонитьJITing , класс загрузки и выгрузки компиляции в реальном времени. Обычно JVM запускает несколько потоков для обработки этой части работы, и числа после имени потока также будут накапливаться, например:CompilerThread1 . |
Concurrent Mark-Sweep GC Thread | JVM | Параллельный поток сборщика мусора с маркировкой и очисткой (так называемый CMS GC), который в основном предназначен для сборки мусора старого поколения. ps: Чтобы включить сборщик мусора, вам нужно добавить следующее в параметры запуска JVM:-XX:+UseConcMarkSweepGC . |
DestroyJavaVM | JVM | воплощать в жизньmain() Поток JNI вызывается после выполнения основного.jni_DestroyJavaVM() метод вызываетDestroyJavaVM Поток в состоянии ожидания уведомляется о необходимости выгрузить JVM, когда он ожидает выхода других потоков (потоков Java и собственных потоков). Когда каждый поток завершается, он определяет, является ли он последним во всей JVM.非deamon线程 , если да, сообщитеDestroyJavaVM Поток выгружает JVM. |
Finalizer Thread | JVM | Этот поток также создается после основного потока, и его приоритет равен 10. Он в основном используется для вызова объекта.finalize() метод; несколько замечаний о потоке Finalizer: 1) Только когда начнется цикл сборки мусора, он начнет вызыватьfinalize() методы, поэтому не все объектыfinalize() метод будет выполнен; 2) поток такжеdaemon поток, поэтому, если в виртуальной машине нет других потоков, не являющихся демонами, не имеет значения, завершил ли поток выполнениеfinalize() метод, JVM также завершит работу; 3) JVM завернет потерянный объект ссылки в сборку мусораFinalizer объект (Reference реализация) и положитьReferenceQueue ,Зависит отFinalizer Поток для обработки; Наконец, ссылка на объект Finalizer устанавливается в значение null и собирается сборщиком мусора; 4) Почему JVM использует отдельный поток для выполненияfinalize() метод? Если поток сборки мусора JVM делает это сам, очень вероятно, что поток GC остановлен или неуправляем из-за неправильной работы в методе finalize(), что является катастрофой для потока GC; |
Low Memory Detector | JVM | Этот поток отвечает за обнаружение доступной памяти, и если доступной памяти оказывается недостаточно, выделение нового пространства памяти. |
Reference Handler | JVM | JVM создаетmain После создания темыReference Handler Поток с наивысшим приоритетом 10 в основном используется для сбора мусора самого ссылочного объекта (мягкая ссылка, слабая ссылка, виртуальная ссылка). |
VM Thread | JVM | Этот поток относительно хорош, и он является матерью потока в JVM.Согласно исходному коду точки доступа (vmThread.hpp ), это единственный объект (самый примитивный поток), который будет генерировать или запускать все остальные потоки, этот единственный поток VM будет использоваться другими потоками для выполнения некоторых операций с VM (таких как: очистка мусора и т. д.). |