📜 ⬆️ ⬇️

What java thread loads my processor

What do you do when your Java application consumes 100% CPU? It turns out that you can easily find problem streams using the built-in Unix and JDK utilities. No profiling tools are required.
For the purpose of testing, we will use a simple program:

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.*"); } } } 

As you can see, in this piece of code 2 threads are launched. Idle does not consume CPU resources (
remember, sleeping threads consume memory, but not the processor), while Busy heavily loads the CPU, performing regular expression parsing, and other complex processes.
How can we quickly find a problem piece of our program code? First, we will use 'top' to find the process Id (PID) of a java application. This is quite simple:
 top -n1 | grep -m1 java 

We will see the first line of the output 'top', containing the word "java":
 22614 tomek 20 0 1360m 734m 31m S 6 24.3 7:36.59 java 

The first column is the PID. Unfortunately, it turned out that 'top' uses ANSI escape codes for colors . Fortunately, I found a perl script to remove the extra characters and finally extract the PID.
 top -n1 | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' ' 

Returns:
 22614 

Now that we know the PID of the process, we can use top -H to search for problematic Linux threads. The -H switch displays a list of all streams, and now the PID column is the stream ID:
 top -n1 -H | grep -m1 java top -n1 -H | grep -m1 java | perl -pe 's/\e\[?.*?[\@-~] ?//g' | cut -f1 -d' ' 

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

Total we have the JVM process ID and the Linux thread ID. And now the most interesting thing: if you look at the jstack output (available in the JDK), each thread has an NID that is written after the name.
 Busy' prio=10 tid=0x7f3bf800 nid=0x6552 runnable [0x7f25c000] java.lang.Thread.State: RUNNABLE at java.util.regex.Pattern$Node.study(Pattern.java:3010) 

The parameter nid = 0x6552 is a Hex thread ID representation:
 printf '%x' 25938 6552 

Now combine everything into one script:
 #!/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 

The last line starts jstack with a specific PID and outputs a stream with a matching NID. That same flow will be problematic.
We carry out:
 ./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) 


A source

')

Source: https://habr.com/ru/post/153135/


All Articles