Какой Поток Java Использует Мой Процессор?

Что вы делаете, когда ваше Java-приложение потребляет 100% ресурсов ЦП? Оказывается, проблемные потоки можно легко найти с помощью встроенных утилит Unix и JDK. Никаких инструментов профилирования не требуется.

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

  
  
  
  
  
  
  
  
  
  
   

public class Main { public static void main(String[] args) { new Thread(new Idle(), "Idle").

start(); new Thread(new Busy(), "Busy").

start(); } } class Idle implements Runnable { @Override public void run() { try { TimeUnit.HOURS.sleep(1); } catch (InterruptedException e) { } } } class Busy implements Runnable { @Override public void run() { while(true) { "Foo".

matches("F.*"); } } }

Как видите, в этом фрагменте кода запускаются 2 потока.

В режиме ожидания не потребляются ресурсы процессора( помните, что спящие потоки потребляют память, но не процессор), в то время как Busy сильно нагружает процессор, выполняя анализ регулярных выражений и другие сложные процессы.

Как мы можем быстро найти проблемный фрагмент кода в нашей программе? Сначала мы будем использовать «top», чтобы найти идентификатор процесса (PID) Java-приложения.

Это довольно просто:

top -n1 | grep -m1 java

Мы увидим первую строку вывода «top», содержащую слово «java»:

22614 tomek 20 0 1360m 734m 31m S 6 24.3 7:36.59 java

Первый столбец — PID. К сожалению, оказывается, что «top» использует Escape-коды ANSI для цветов .

К счастью, я нашел Perl-скрипт для удаления лишних символов и, наконец, извлечения PID.

top -n1 | grep -m1 java | perl -pe 's/\e\[?.

*?[\@-~] ?//g' | cut -f1 -d' '

Возврат:

22614

Теперь, когда мы знаем PID процесса, мы можем использовать top -H для поиска проблемных потоков Linux. Переключатель -H отображает список всех потоков, и теперь столбец PID — это идентификатор потока:

top -n1 -H | grep -m1 java top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.

*?[\@-~] ?//g' | cut -f1 -d' '

Возврат:

25938 tomek 20 0 1360m 748m 31m S 2 24.8 0:15.15 java 25938

Итого у нас есть идентификатор процесса JVM и идентификатор потока Linux. Теперь самое интересное: если вы посмотрите на выходные данные jstack (доступны в JDK), каждый поток имеет NID, который пишется после имени.



Busy' prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000] java.lang.Thread.State: RUNNABLE at java.util.regex.Pattern$Node.study(Pattern.java:3010)

Параметр nid=0x6552 представляет собой шестнадцатеричное представление идентификатора потока:

printf '%x' 25938 6552

Теперь объединим все в один скрипт:

#!/bin/bash PID=$(top -n1 | grep -m1 java | perl -pe 's/\e\[?.

*?[\@-~] ?//g' | cut -f1 -d' ') NID=$(printf '%x' $(top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.

*?[\@-~] ?//g' | cut -f1 -d' ')) jstack $PID | grep -A500 $NID | grep -m1 '^$' -B 500

Последняя строка запускает jstack с определенным PID и выводит поток с соответствующим NID. Тот же поток будет проблематичным.

Мы делаем:

.

/profile.sh "Busy" prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000] java.lang.Thread.State: RUNNABLE at java.util.regex.Pattern$Node.study(Pattern.java:3010) at java.util.regex.Pattern$Curly.study(Pattern.java:3854) at java.util.regex.Pattern$CharProperty.study(Pattern.java:3355) at java.util.regex.Pattern$Start.<init>(Pattern.java:3044) at java.util.regex.Pattern.compile(Pattern.java:1480) at java.util.regex.Pattern.<init>(Pattern.java:1133) at java.util.regex.Pattern.compile(Pattern.java:823) at java.util.regex.Pattern.matches(Pattern.java:928) at java.lang.String.matches(String.java:2090) at com.blogspot.nurkiewicz.Busy.run(Main.java:27) at java.lang.Thread.run(Thread.java:662)

Источник Теги: #java #threads #java

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.