Диагностика Java-приложения с jvisualvm

В составе JDK есть полезная утилита jvisualvm (Java VisualVM), позволяющая снимать дампы, анализировать производительность, состояние потоков и памяти.

Для анализа создадим вот такую программу на Java «MainTestProgram.java»:

Скомпилируем (в случае проблем рекомендую ознакомиться с вот этой статьей):

И запустим на выполнение:

Теперь перейдём в каталог bin внутри JDK. У меня для Windows это было «C:\Program Files\Java\jdk1.8.0_91\bin», но у вас он может немного отличаться в зависимости от версии Java и операционной системы.

Запустим jvisualvm. В левой части окна Java VisualVM в дереве кликнем два раза на нашей программе MainTestProgram:

Java VisualVM

Должна появиться вкладка MainTestProgram (pid NNNN). Внутри неё будет ещё пять вкладок:

  1. Overview;
  2. Monitor;
  3. Threads;
  4. Sampler;
  5. Profiler;

На вкладке Overview отображается общая информация о версии Java-машины, системных параметрах и прочем.

На вкладке Monitor можно смотреть загрузку ЦП, выделение памяти, количество запущенных и активных потоков. Здесь можно заметить моменты работы сборщика мусора. Для нашей программы там будет отображено примерно такое:

Monitor, Memory, CPU, Threads, jvisualvm, Java

Обратите внимание на правый верхний график. График Used heap постоянно растёт. Можно смотреть на него очень долго, но даже если будет происходить сборка мусора, то график всё равно будет продвигаться вверх. Это сигнализирует о возможной утечке памяти. В нашем случае это происходит в строках concurrentMap.put(, где мы постоянно создаём новые значения и кладём их в глобальный ConcurrentMap, в результате чего они всегда достижимы из кода и никогда не уничтожаются сборщиком мусора. В реальных приложениях найти причину утечки гораздо сложнее.

На вкладке Threads отображается состояние потоков. Для нашего случая это нечто такое:

Java VisualVM Threads

Обратите внимание на потоки pool-1-thread-NN. Они все в состоянии Park, то есть чего-то ожидают. Когда все потоки из пулов находятся в таком состоянии, то это тоже плохой признак. Они могут ожидать ответа от другого сервера по сети или ещё чего-нибудь. В нашем случае они сидят в строке  Thread.sleep(500L);  нашего кода, что мы увидим в последующих вкладках Java VisualVM.

На вкладке Sampler мы можем замерять, количество созданных объектов каждого типа и количество затраченного времени на вызов каждого метода.

jvisualvm, sampler, cpu, memory

Для замера времени выполнения методов нужно кликнуть по кнопке CPU, после чего jvisualvm начнёт собирать данные. Можно делать snapshot-ы для сохранения в файл и последующего анализа:

java VisualVM CPU snapshot

Как вы можете увидеть, все потоки действительно висят на нашем Thread.sleep:

jvisualvm CPU snapshot

Теперь посмотрим на состояние памяти. Для этого снова вернитесь во вкладке Sampler и кликните на кнопку Memory, после чего jvisualvm начнёт собирать статистику использования памяти:

Java VisualVM memory

Информации, которую я уже изложил в статье, должно хватить для выявления большинства проблем и узких мест в вашем приложении. Осталось сказать ещё только одно: как подключиться к удалённому приложению на сервере?

Для подключения к приложению на удалённом сервере нужно сперва запустить на этом сервере утилиту jstatd, которая входит в состав JDK. Затем кликаем правой кнопкой мышки на узле Remote в jvisualvm и там на Add Remote Host…, после чего в появившемся окне необходимо указать имя узла и отображаемое имя. В остальном работа с удалённым приложением аналогична анализу локального приложения.


Поделиться:

Добавить комментарий

Ваш e-mail не будет опубликован.

*