Инструмент мониторинга настройки производительности JVM

JVM Linux

Эта статья в основном учит записывать часто используемые в работеJDKпринести некоторыеJVMИнструменты настройки и мониторинга производительности, понимая эти инструменты, могут дать нам большую помощь при устранении неисправностей проблем и принести некоторые скрытые вещи на поверхность для анализа.

jps(Java Virtual Machine Process Status Tool)

jpsВ основном используется для выводаJVMИнформация о состоянии процессов, запущенных в . Формат синтаксиса следующий:

jps [options] [hostid]

Если не указаноhostidПоскольку по умолчанию используется текущий хост или сервер, параметры командной строки описываются следующим образом:

-q Не выводить имя класса, имя Jar и параметры, переданные в основной метод

➜  ~ jps -q
42060

-m выводить аргументы, переданные основному методу (та же информация, что возвращается командой jps по умолчанию)

➜  ~ jps -m
42060 TestSofaBootApplication

-l напечатать полное имя основного класса или jar

➜  ~ jps -l
42060 com.glmapper.bridge.boot.TestSofaBootApplication

-v выходные аргументы, переданные в JVM

➜  ~ jps -v
42060 TestSofaBootApplication -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:51645,suspend=y,server=n -XX:TieredStopAtLevel=1 -Xverify:none -Dspring.output.ansi.enabled=always -Dcom.sun.management.jmxremote -Dspring.jmx.enabled=true -Dspring.liveBeansView.mbeanDomain -Dspring.application.admin.enabled=true -javaagent:/Users/xxxx/Library/Caches/JetBrains/IntelliJIdea2020.1/captureAgent/debugger-agent.jar -Dfile.encoding=UTF-8

При устранении неполадок мы проходим пройдемjpsДавайте посмотрим на процессы, запущенные на текущей машине, и используем различные параметры, чтобы быстро найти местоположение нашего целевого процесса.pid, чтобы облегчить нашу последующую серию операций по устранению неполадок.

jstack(Java Stack Trace)

jstackВ основном используется для просмотраJavaИнформация о стеке потоков внутри процесса. еслиjavaПрограмма аварии генерацииcoreдокумент,jstackсредства можно использовать для полученияcoreдокументjava stackиnative stackинформацию, чтобы вы могли легко узнатьjavaКак происходит сбой программы и где возникает проблема в программе. Кроме того,jstackИнструменты также могут быть прикреплены к запускуjavaВ программе я видел его работающим в то время.javaпроцедурныйjava stackиnative stackинформация, если в настоящее время работаетjavaРендеринг программыhungстатус,jstackочень полезно.

НижеjstackФормат синтаксиса:

jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip

Независимо от того, что это за команда, мы должны сначала научиться проверять ее с помощью -h

➜  ~ jstack -h
Usage:
    jstack [-l] <pid>
        (连接到正在运行的进程)
    jstack -F [-m] [-l] <pid>
        (连接到挂起的进程)
    jstack [-m] [-l] <executable> <core>
        (连接到 core 文件)
    jstack [-m] [-l] [server_id@]<remote server IP or hostname>
        (连接到远程调试服务器)

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

OptionsОписание параметра выглядит следующим образом:

опции эффект
-F Когда обычный запрос вывода не отвечает, принудительно стек потока вывода
-m Если вызов локального метода, то можно отобразить стек C/C++
-l В дополнение к стеку отображается дополнительная информация о блокировке.В случае взаимоблокировки вы можете использовать jstack -l pid для наблюдения за состоянием удержания блокировки.

Давайте сосредоточимся на разговоре о том,jstackКак посмотреть информацию.

введение информации о стеке jstack

Нижеjstackраздел выводаtacerданные

"main" #1 prio=5 os_prio=31 tid=0x00007fb93b802000 nid=0x2703 waiting on condition [0x0000700005e5d000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.glmapper.bridge.boot.TestJstack.testWaitingOnConditionCondition(TestJstack.java:19)
	at com.glmapper.bridge.boot.TestJstack.main(TestJstack.java:10)

С этими данными мы, вероятно,getПункты, которые необходимо посетить, в основном включают следующую информацию:

  • имя основного потока
  • #1 Порядковый номер стека не имеет фактического значения и может быть проигнорирован
  • приоритет приоритета потока
  • os_prio приоритет на уровне ОС
  • идентификатор потока
  • идентификатор нид-треда

Введение в состояние потока

Из информации, выводимой jstack выше, вы можете увидеть информацию, относящуюся к статусу потока, такую ​​как

TIMED_WAITING

java.lang.Thread.State: TIMED_WAITING (sleeping)

RUNNABLE

java.lang.Thread.State: RUNNABLE

еще чуть-чуть"GC task thread#0 (ParallelGC)" os_prio=31 tid=0x00007fcee9004000 nid=0x1f07 runnableИнформация, это используется jvm для восстановления памяти, не обращайте на это внимание, вот основной видjava.lang.Thread.State;

public enum State {
    /**
     * 当线程对象创建时存在的状态,此时线程不可能执行
     */
    NEW,
   /**
    * 当调用thread.start()后,线程变成为 Runnable 状态。只要得到CPU,就可以执行;
    */
    RUNNABLE,
    /**
     * 如果进入同步方法或同步代码块,没有获取到锁,则会进入该状态;
     */
    BLOCKED,
    /**
     * 执行thread.join()或在锁对象调用obj.wait()等情况就会进该状态,表明线程正处于等待某个资源或条件发生来唤醒自己;
     */
    WAITING,
    /**
     * 执行Thread.sleep(long)、thread.join(long)或obj.wait(long)等就会进该状态,与Waiting的区别在于Timed_Waiting的等待有时间限制;
     */
    TIMED_WAITING,
    /**
     * 终止
     */
    TERMINATED;
}

Возвращаясь к приведенной выше информации о стеке, можно заметить, что когда состояние TIMED_WAITING, стек появитсяwaiting on condition xxxxинформация, похожая на:

  • В ожидании записи монитора: ждет, чтобы приобрести замок, как правило, соответствует заблокированному
  • в Object.wait(): после получения блокировки выполните obj.wait(), чтобы отказаться от блокировки, обычно это соответствует ОЖИДАНИЮ

Вот несколько простых примеров таких состояний.

Пример статуса потока и анализ jstack

waiting on condition

1. Выполнить код

/**
 * 产生 waiting on condition
 */
private static void testWaitingOnConditionCondition(){
    while (true){
        try {
            Thread.sleep(60000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

2. Результаты исполнения

"main" #1 prio=5 os_prio=31 tid=0x00007fb93b802000 nid=0x2703 waiting on condition [0x0000700005e5d000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.glmapper.bridge.boot.TestJstack.testWaitingOnConditionCondition(TestJstack.java:19)
	at com.glmapper.bridge.boot.TestJstack.main(TestJstack.java:10)

3. Анализ результатов

Здесь очевидно, что основной поток находится в методе сна. Однако скобки после TIMED_WAITING здесь также специально указываютsleeping, в некоторых сценариях парковка является обычным явлением, см. примеры ниже.

waiting on condition (parking)

1. Выполнить код

private static void testWaitingOnConditionConditionWithParking(){
    // 提供一个阻塞对了
    BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(1);
    // 先加一个
    blockingQueue.add("test-parking");
    try {
        //继续加,这里肯定加不进去,所以会阻塞
        blockingQueue.put("test-parking-xxx");
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

2. Результаты исполнения

"main" #1 prio=5 os_prio=31 tid=0x00007fd6d5008800 nid=0x2803 waiting on condition [0x000070000ffc1000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x000000076af3a938> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:353)
	at com.glmapper.bridge.boot.TestJstack.testWaitingOnConditionConditionWithParking(TestJstack.java:113)
	at com.glmapper.bridge.boot.TestJstack.main(TestJstack.java:13)

3. Анализ результатов

Основной поток входит в состояние ожидания в состоянии, ожидая определенного ресурса, вы можете видеть, что он находится в состоянии ожидания.a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObjecПодождал, заблокировал.

waiting on monitor entry

1. Выполнить код

/**
 * 产生 waiting on monitor entry
 */
private static void testWaitingOnMonitorEntry(){
    final Object obj = new Object();
    final Thread thread = new Thread(){
        @Override
        public void run() {
            // 锁 obj 对象
            synchronized (obj){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(60000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    final Thread thread1 = new Thread(){
        @Override
        public void run() {
            // 锁 obj 对象
            synchronized (obj){
                System.out.println(Thread.currentThread().getName());
                try {
                    Thread.sleep(60000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    thread.setName("test-thread");
    thread.start();
    thread1.setName("test-thread1");
    thread1.start();
}

2. Результаты исполнения

"test-thread1" #14 prio=5 os_prio=31 tid=0x00007f9563880800 nid=0x5c03 waiting for monitor entry [0x000070000b029000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at com.glmapper.bridge.boot.TestJstack$2.run(TestJstack.java:50)
	- waiting to lock <0x000000076af261d0> (a java.lang.Object)

"test-thread" #13 prio=5 os_prio=31 tid=0x00007f956387f800 nid=0x5a03 waiting on condition [0x000070000af26000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.glmapper.bridge.boot.TestJstack$1.run(TestJstack.java:38)
	- locked <0x000000076af261d0> (a java.lang.Object)

3. Анализ результатов

Тестовый поток получил блокировку объекта obj, поэтому он выполняет операцию ожидания, и состояние TIMED_WAINTING, в то время как тестовый поток1 находится в состоянии BLOCKED, поскольку он не получил блокировку объекта obj.

test-thread1 "ожидает блокировки ", пытаясь заблокировать объект по адресу 0x000000076af261d0, который удерживается потоком test-thread [заблокирован ]. Поток тестового потока «ожидает условия», что указывает на то, что он ожидает срабатывания условия.Согласно jstack, этот поток находится в спящем режиме.

object.wait()

1. Выполнить код

private static void testObjectWait() {
    final Thread thread = new Thread() {
        @Override
        public void run() {
            synchronized (this) {
                System.out.println(Thread.currentThread().getName());
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    };
    thread.start();
    thread.setName("test-object-wait");
    try {
        Thread.sleep(5000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    synchronized (thread) {
        System.out.println(Thread.currentThread().getName());
        try {
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.notify();
    }
}

2. Результаты исполнения

"test-object-wait" #13 prio=5 os_prio=31 tid=0x00007fd43a809000 nid=0xa803 in Object.wait() [0x0000700010926000]
   java.lang.Thread.State: WAITING (on object monitor)
	at java.lang.Object.wait(Native Method)
	- waiting on <0x000000076af26140> (a com.glmapper.bridge.boot.TestJstack$3)
	at java.lang.Object.wait(Object.java:502)
	at com.glmapper.bridge.boot.TestJstack$3.run(TestJstack.java:73)
	- locked <0x000000076af26140> (a com.glmapper.bridge.boot.TestJstack$3)

"main" #1 prio=5 os_prio=31 tid=0x00007fd43b001800 nid=0x2603 waiting on condition [0x000070000f2e4000]
   java.lang.Thread.State: TIMED_WAITING (sleeping)
	at java.lang.Thread.sleep(Native Method)
	at com.glmapper.bridge.boot.TestJstack.testObjectWait(TestJstack.java:93)
	- locked <0x000000076af26140> (a com.glmapper.bridge.boot.TestJstack$3)
	at com.glmapper.bridge.boot.TestJstack.main(TestJstack.java:10)

3. Анализ результатов

Поскольку блокировка снимается при вызове метода object.wait(), поэтомуtest-object-waitЭтот поток появляется в состоянии Object.wait(), а состояние потока — ожидание, ожидание пробуждения уведомления. Так как поток mian получаетtest-object-waitПосле блокировки потока вызывается метод Thread.sleep, поэтому в это время он входит в состояние ожидания для ожидания определенного ресурса и переходит в состояние time_waiting.

резюме

В общем, когда мы занимаемся устранением неполадок, если система очень медленная, нам нужно обратить особое вниманиеBlocked,Waiting on conditionэти состояния. Если загрузка ЦП системы относительно высока, вы можете проверить ее с помощью таких идей, как бесконечные циклы.В это время вы должны обратить внимание на следующееRunableсостояние; если в стеке естьDeadlock, то есть возникает взаимоблокировка.

jstat (инструмент мониторинга статистики JVM)

jstatЭто инструмент статистического мониторинга JVM, и его синтаксис выглядит следующим образом:

jstat -<option> [-t] [-h<lines>] <vmid> [<interval> [<count>]]

vmidдаJavaвиртуальная машинаID,существуетLinux/UnixСистема, как правило, является процессомID.intervalинтервал времени выборки;countэто количество образцов. Например, следующий выводGCИнформация, интервал выборки 1000 мс, количество выборок 3:

➜  ~ jstat -gc 58950 1000 3
S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT
10752.0 10752.0  0.0    0.0   65536.0   6554.0   175104.0     0.0     4480.0 785.7  384.0   75.9       0    0.000   0      0.000    0.000
10752.0 10752.0  0.0    0.0   65536.0   6554.0   175104.0     0.0     4480.0 785.7  384.0   75.9       0    0.000   0      0.000    0.000
10752.0 10752.0  0.0    0.0   65536.0   6554.0   175104.0     0.0     4480.0 785.7  384.0   75.9       0    0.000   0      0.000    0.000

Определение столбца выходной информации:

  • S0C, S1C, S0U, S1U: вместимость области Survivor 0/1 (емкость) и использование (использовано)
  • EC, EU: Емкость и использование зоны Eden
  • OC, OU: старая генерирующая мощность и использование
  • ПК, ПУ: постоянная генерирующая мощность и использование
  • YGC, YGT: время GC для молодого поколения и время GC
  • FGC, FGCT: время полного GC и время полного GC
  • GCT: общее время GC

jmap(Memory Map)

jmapИспользуется для просмотра использования памяти кучи, обычно в сочетании сjhatиспользовать. Синтаксис его использования следующий:

jmap [option] <pid>
jmap [option] <executable <core>
jmap [option] [server_id@]<remote server IP or hostname>

OptionsОписание параметра выглядит следующим образом:

опции эффект
печатать сSolaris pmapта же информация
-heap Распечататьjavaсводка кучи
-histo[:live] Вывести гистограмму кучи java-объектов, если указана подопция «живые», учитываются только живые объекты
-clstats распечатать статистику загрузчика классов
-finalizerinfo Распечатать информацию об объекте, ожидающем завершения
--dump: : дамп кучи java в двоичном формате hprof
-F Принудительно используйте -dump: или -histo
-J Переход непосредственно в систему выполнения

dump-options также включает следующие параметры:

  • live : выгружать только живые объекты; если не указано, будут выгружены все объекты в куче.
  • format=b : двоичный формат
  • file= : дамп в указанный файл

jmap -heap

указавpid, вы можете преобразовать текущий процессheapИнформационная печатьconsoleв том числе с использованиемGCАлгоритм, параметры конфигурации кучи и использование памяти кучи в каждом поколении следующие:

$ jmap -heap 3493
Attaching to process ID 3493, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.172-b245

using parallel threads in the new generation.(eden 区使用的是并发线程)
using thread-local object allocation.(使用线程本地对象分配)
Concurrent Mark-Sweep GC (使用 CMS 垃圾收集器)
# 堆配置信息
Heap Configuration:
   MinHeapFreeRatio         = 40
   MaxHeapFreeRatio         = 70
   MaxHeapSize              = 2147483648 (2048.0MB)
   NewSize                  = 805306368 (768.0MB)
   MaxNewSize               = 805306368 (768.0MB)
   OldSize                  = 1342177280 (1280.0MB)
   NewRatio                 = 2
   SurvivorRatio            = 8
   MetaspaceSize            = 21807104 (20.796875MB)
   CompressedClassSpaceSize = 1073741824 (1024.0MB)
   MaxMetaspaceSize         = 17592186044415 MB
   G1HeapRegionSize         = 0 (0.0MB)

# 堆使用情况
Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 724828160 (691.25MB)
   used     = 35156456 (33.527809143066406MB)
   free     = 689671704 (657.7221908569336MB)
   4.850315970063856% used
Eden Space:
   capacity = 644349952 (614.5MB)
   used     = 19878008 (18.95714569091797MB)
   free     = 624471944 (595.542854309082MB)
   3.084970820328392% used
From Space:
   capacity = 80478208 (76.75MB)
   used     = 15278448 (14.570663452148438MB)
   free     = 65199760 (62.17933654785156MB)
   18.984577787815553% used
To Space:
   capacity = 80478208 (76.75MB)
   used     = 0 (0.0MB)
   free     = 80478208 (76.75MB)
   0.0% used
concurrent mark-sweep generation:
   capacity = 1342177280 (1280.0MB)
   used     = 166885296 (159.1542205810547MB)
   free     = 1175291984 (1120.8457794189453MB)
   12.433923482894897% used

55843 interned Strings occupying 6689024 bytes.

jmap -clstats

Указав pid, статистика загрузчика классов текущего процесса может быть напечатана на консоли, включая имя загрузчика классов, жив ли объект, адрес объекта, родительский загрузчик классов, размер загруженного класса и т. д., как показано ниже:

$ jmap -clstats  3493
Attaching to process ID 3493, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.172-b245
finding class loader instances ..done.
computing per loader stat ..done.
please wait.. computing liveness.......................liveness analysis may be inaccurate ...
class_loader	classes	bytes	parent_loader	alive?	type

<bootstrap>	3211	5818395	  null  	live	<internal>
0x00000000b150ed50	1	1491	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b8715670	1	900	    0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000cb417140	1	1503	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b98b4388	1	1491	  null  	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b5a419a0	1	900	    0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b358df50	1	1493	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b7b277b8	1	1503	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000c2527c58	1	1505	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b98b4580	1	1491	0x00000000b0026260	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b9b307b8	1	1493	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000e236b038	1	900	    0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b0108400	1	1493	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040
0x00000000b010bc00	3	7946	0x00000000b0022f60	live	org/jacoco/compass/agent/rt/internal/fastjson/util/ASMClassLoader@0x00000001000eb830
0x00000000b358e148	1	1493	0x00000000b0020830	dead	sun/reflect/DelegatingClassLoader@0x000000010000a040

jmap -histo

Используйте jmap -histo pid для просмотра количества объектов в куче памяти, гистограммы статистики размера, как показано ниже:

# jmap -histo:live 1493  带上 live 则只统计存活对象
$ jmap -histo 1493  
num     #instances         #bytes  class name
----------------------------------------------
   1:       1314509      144436976  [C
   2:       1572864       37748736  org.apache.logging.log4j.core.async.AsyncLoggerConfigDisruptor$Log4jEventWrapper
   3:         77458       32776608  [B
   4:       1061561       25477464  java.lang.String
   5:        731623       23411936  java.util.HashMap$Node
   6:         32930       22826616  [I
   7:        150340       15546784  [Ljava.util.HashMap$Node;
   8:        144895       14968208  [Ljava.lang.Object;
   9:        377379       12076128  java.util.concurrent.ConcurrentHashMap$Node
  10:        230943       11085264  java.util.HashMap
  11:         81124        3893952  java.nio.HeapByteBuffer
  12:          3396        3869944  [Ljava.util.concurrent.ConcurrentHashMap$Node;
  13:         78418        3764064  java.nio.HeapCharBuffer
  14:         75784        3031360  java.util.TreeMap$Entry
  15:         72865        2914600  java.util.LinkedHashMap$Entry
  16:        166213        2659408  java.util.HashSet
  17:         18355        2643120  com.mysql.jdbc.Field
  18:         18394        2044336  java.lang.Class
  19:         19966        1757008  java.lang.reflect.Method

PS: [C [B на приведенном выше рисунке относится к типу объекта класса, а следующее является ссылкой на общие типы

  • B byte
  • C char
  • D double
  • F float
  • I int
  • J long
  • Z boolean
  • [Массив, например [я для INT []
  • [L+имя класса Другие объекты, такие как [Ljava.lang.Object

jmap -dump

В большинстве случаев мы не будем выводить анализ прямо в консоль.Более традиционный подход состоит в том, чтобы сделать дамп в указанный файл, а затем использовать некоторые визуальные инструменты для помощи в анализе, а затем выполнить дамп в файл, следующие команды обычно используются:

jmap -dump:format=b,file=dumpFileName pid   # 语法

$ jmap -dump:format=b,file=test-dump.bin 85716  # 举例
Dumping heap to /Users/guolei.sgl/test-dump.bin ...
Heap dump file created

Для анализа файлов дампа вы можете использовать графические инструменты, такие как jprofile, следующим образом.

Вы также можете просмотреть его через jhat, метод работы следующий:

1. Запустите http-сервис

jhat -port 9300 test-dump.bin
Reading from test-dump.bin...
Dump file created Wed Oct 28 17:54:24 CST 2020
Snapshot read, resolving...
Resolving 1151952 objects...
Chasing references, expect 230 dots......................................................................................................................................................................................................................................
Eliminating duplicate references......................................................................................................................................................................................................................................
Snapshot resolved.
Started HTTP server on port 9300
Server is ready.

2. Сводная информация о классе дампа

Посетите localhost: 9300 для просмотра сводной информации свалки

3, детали класса

Нажмите на класс, чтобы просмотреть подробности

резюме

В этой статье представлены некоторые инструменты мониторинга настройки производительности, которые поставляются с JDK. Освоив эти инструменты, мы можем быстро найти и решить некоторые проблемы в фактической разработке или эксплуатации и обслуживании. Наиболее распространенными из них являются OOM, утечки памяти, взаимоблокировки потоков, высокая загрузка ЦП, д.; в сообществе также есть много полезных инструментов, таких какArthas,perfmaЖдать.