foreword
This article belongs to the column "100 Questions to Solve the Java Virtual Machine". This column is original by the author. Please indicate the source for the reference. Please help point out the shortcomings and mistakes in the comment area, thank you!
For the directory structure and literature citations of this column, please refer to 100 questions to solve the Java virtual machine
Primer
Arthas
It is an open source Java diagnostic tool of Alibaba, which is very popular among developers.
When you encounter the following similar problems and feel at a loss, Arthas
we can help you solve them:
- Which jar package is this class loaded from? Why are various types of related Exception reported?
- Why is the code I changed not executed? Could it be that I didn't commit? Branching wrong?
- If you encounter a problem and cannot debug online, can you only republish it by adding a log?
- I encountered a problem with the data processing of a certain user online, but it also cannot be debugged online, and cannot be reproduced offline!
- Is there a global view into the health of the system?
- Is there any way to monitor the real-time running status of the JVM?
- How to quickly locate application hotspots and generate flame graphs?
- How to find an instance of a class directly from within the JVM?
Xiao Ming opened Artha
the official document Arthas User Documentation — Arthas 3.5.2 Documentation (aliyun.com)
This is the first sentence I saw
So I started to read the document
After reading it with great effort, Xiao Ming found that the official did not give a standard solution to the above problem.
Isn't this killing or burying! ! !
text
The following is the author's detailed solutions to these 8 problems based on years of experience in using Arthas. If you have any questions, please point them out in the comment area.
Prepare
First give my test code
package com.shockang.study;
import com.alibaba.fastjson.JSON;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldDefaults;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class ArthasDemo {
public static void main(String[] args) {
String s = "[{\"name\":\"zhangsan\",\"age\":\"10\",\"telephone\":\"123456\",\"interests\":[\"sing\",\"dance\",\"rap\"]},\n" +
"{\"name\":\"lisi\",\"age\":\"20\",\"telephone\":\"123457\",\"interests\":[\"sing\",\"swim\"]},\n" +
"{\"name\":\"wangwu\",\"age\":\"30\",\"telephone\":\"123458\",\"interests\":[\"sing\",\"program\"]}]";
//模拟一遍遍的调用方法的过程
for (; ; ) {
System.out.println(new ArthasDemo().convert(s));
try {
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private List<People> convert(String s) {
return JSON.parseArray(s, People.class);
}
@Getter
@Setter
@ToString
@FieldDefaults(level = AccessLevel.PRIVATE)
private static class People {
/**
* 姓名
*/
String name;
/**
* 年龄
*/
String age;
/**
* 电话
*/
String telephone;
/**
* 兴趣列表
*/
List<String> interests;
}
}
The following is the result of normal printing on the console
/Library/Java/JavaVirtualMachines/jdk1.8.0_192.jdk/Contents/Home/bin/java ...
[ArthasDemo.People(name=zhangsan, age=10, telephone=123456, interests=[sing, dance, rap]), ArthasDemo.People(name=lisi, age=20, telephone=123457, interests=[sing, swim]), ArthasDemo.People(name=wangwu, age=30, telephone=123458, interests=[sing, program])]
[ArthasDemo.People(name=zhangsan, age=10, telephone=123456, interests=[sing, dance, rap]), ArthasDemo.People(name=lisi, age=20, telephone=123457, interests=[sing, swim]), ArthasDemo.People(name=wangwu, age=30, telephone=123458, interests=[sing, program])]
Download and run Arthas, select a Java process to attach
After the attach is successful, you can open Google Chrome and enter http://127.0.0.1:3658/ to open WebConsole
(Tucao a Mac OS Safari browser does not support)
The most convenient thing about using WebConsole is that you can open multiple tabs to operate at the same time
Question 1: Which jar package is this class loaded from? Why are various types of related Exception reported?
I often encounter this problem when dealing with various dependency conflicts . The full names of some classes are exactly the same, and it is impossible to solve which jar package the class is loaded from by conventional methods.
Don't worry, see my solution below.
- sc
Use sc
the command to vaguely check whether the class containing the keyword is loaded in the current JVM, and get its full name.
Pay attention to use
sc -d
the command to get classLoaderHash, this value will be used later.
sc -d *ArthasDemo*
- classloader
By classloader
viewing which jar package the class file comes from
Use
cls
the command to clear the command line, but the official documentation for this simple command cannot be found. . .
classloader -c
Note Fill in the Hash value obtained in the first step above for the following value. The class file path is separated by '/' and must end with .class.
[arthas@3633]$ classloader -c 18b4aac2 -r com/shockang/study/ArthasDemo.class
file:/Users/shockang/code/concurrentbook/target/classes/com/shockang/study/ArthasDemo.class
Affect(row-cnt:1) cost in 0 ms.
The above shows the path of the class file. If the class file comes from the jar package, the path of the jar package can be displayed, such as the example given in the official document:
$ classloader -c 1b6d3586 -r java/lang/String.class
jar:file:/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home/jre/lib/rt.jar!/java/lang/String.class
Question 2: Why is the code I changed not executed? Could it be that I didn't commit? Branching wrong?
It is recommended to use watch
the and tt
commands, which are very easy to use.
These two commands are used to view the method calling process. The difference is that watch
the command prints the calling situation of a method once called, while tt
the command can first generate an ever-increasing calling list, and then specify one of them for observation.
- Use
watch
the command to view method calls. We want to check the convert method call in the ArthasDemo class.
watch com.shockang.study.ArthasDemo convert "{params,target,returnObj}" -f -x 4
watch
Followed by the full class name and method name, and an OGNL expression, -f means to observe whether it returns normally or abnormally, -x means the attribute traversal depth of the output result, the default is 1,
It is recommended to write 4 without thinking. This is the largest traversal depth from the author's experience. No matter how big it is, it will not support it.
- Use
tt
the command to observe the method call.tt
The command can view multiple calls and select one of them to observe, but if the output result is multi-level nesting, there is no way to see it.watch
You can view the results of multi-level nesting .
Use tt -t to record the environment scene of each call of the current method
tt -t com.shockang.study.ArthasDemo convert
TIMESTAMP indicates the time when the method call occurs, COST indicates the call time (ms), IS-RET indicates whether it returns normally, IS-EXP indicates whether it returns abnormally, and OBJECT indicates the hash value of the object
For the information of a specific time slice, you can view its detailed information through the -i parameter followed by the corresponding INDEX number
The reason why the interest list can be printed in the figure is that its toString method is called. If the toString method of the java.lang.Object class is not rewritten, only the hash value will be seen.
- How to judge whether the code has been submitted?
jad --source-only
You can view the source code via .
[arthas@3633]$ jad --source-only com.shockang.study.ArthasDemo
/*
* Decompiled with CFR.
*/
package com.shockang.study;
import com.alibaba.fastjson.JSON;
import java.util.List;
import java.util.concurrent.TimeUnit;
public class ArthasDemo {
public static void main(String[] args) {
/*15*/ String s = "[{
\"name\":\"zhangsan\",\"age\":\"10\",\"telephone\":\"123456\",\"interests\":[\"sing\",\"dance\",\"rap\"]},\n{
\"name\":\"lisi\",\"age\":\"20
\",\"telephone\":\"123457\",\"interests\":[\"sing\",\"swim\"]},\n{
\"name\":\"wangwu\",\"age\":\"30\",\"telephone\":\"123458\",\"interests\":[\"sing\",\"program\"]}]";
while (true) {
/*20*/ System.out.println(new ArthasDemo().convert(s));
try {
/*22*/ TimeUnit.SECONDS.sleep(10L);
/*25*/ continue;
}
catch (InterruptedException e) {
/*24*/ e.printStackTrace();
continue;
}
break;
}
}
private List<People> convert(String s) {
/*30*/ return JSON.parseArray(s, People.class);
}
private static class People {
private String name;
private String age;
private String telephone;
private List<String> interests;
private People() {
}
public String toString() {
return "ArthasDemo.People(name=" + this.getName() + ", age=" + this.getAge() + ", telephone=" + this.getTelephone() + ", interests=" + this.getIntere
sts() + ")";
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return this.age;
}
public String getTelephone() {
return this.telephone;
}
public List<String> getInterests() {
return this.interests;
}
public void setAge(String age) {
this.age = age;
}
public void setTelephone(String telephone) {
this.telephone = telephone;
}
public void setInterests(List<String> interests) {
this.interests = interests;
}
}
}
[arthas@3633]$
Question 3: If you encounter a problem and cannot debug online, can you only republish it by adding a log?
You can view the method calls through the watch
and .tt
In addition, the code on the line can redefine
be hot-replaced through the command , and it will be invalid after the application is restarted, which will work wonders in some emergency situations.
For example, let's modify the code in the method body and add a line of log printing:
private List<People> convert(String s) {
System.out.println(s);
return JSON.parseArray(s, People.class);
}
At this point, we can hot replace the running ArthasDemo code with the compiled class file of the new code.
From this picture, it can be clearly seen that there is no logic to print the string s in the source code, but the console still prints the string, because we have hot replaced the class loaded in the JVM memory (method area).
Question 4: There is a problem with the data processing of a certain user online, but it cannot be debugged online, and cannot be reproduced offline!
There is no perfect solution to this problem
Please refer to the solution of problem 2 and problem 3
It is recommended to use tt
the command and output the result returned by the command line to a file, and then you can select a line of abnormal records and use tt -i
the command for in-depth analysis.
tee
The command reads data from the standard input device, outputs its content to the standard output device, and saves it as a file.
tt -t com.shockang.study.ArthasDemo convert | tee /Users/shockang/Downloads/log
In addition, you can also use monitor
the command to count the success and failure of the method call.
monitor -c 30 com.shockang.study.ArthasDemo convert | tee /Users/shockang/Downloads/log1
-c is followed by the statistical period, the default value is 120 seconds
Question 5: Is there a global perspective to see the health of the system?
Use dashboard
the command to view the real-time data panel of the current system
. When running on Ali-tomcat, it will display the real-time information of the current tomcat, such as HTTP request qps, rt, error number, thread pool information, etc.
From the figure, you can see the thread status, memory usage, system parameters, etc.
Question 6: Is there any way to monitor the real-time running status of the JVM?
Use jvm
the command to view the real-time running status of the JVM.
Question 7: How to quickly locate application hotspots and generate flame graphs?
profiler
The command supports generating flame graphs of application hotspots. Essentially, through continuous sampling, the collected sampling results are then generated into flame graphs.
By default, the flame graph of the cpu is generated, that is, the event is the cpu, which can be specified with the –event parameter. Note that different systems support different events
By default, arthas uses port 3658, you can open: http://localhost:3658/arthas-output/ to view the profiler results under the arthas-output directory:
select an item click
Question 8: How to find an instance of a class directly from the JVM?
use vmtool
can achieve the purpose
This feature is new in Arthas 3.5.1. You can refer to the official document vmtool — Arthas 3.5.2 Documentation (aliyun.com)
$ vmtool --action getInstances --className java.lang.String --limit 10
@String[][
@String[com/taobao/arthas/core/shell/session/Session],
@String[com.taobao.arthas.core.shell.session.Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/taobao/arthas/core/shell/session/Session.class],
@String[com/],
@String[java/util/concurrent/ConcurrentHashMap$ValueIterator],
@String[java/util/concurrent/locks/LockSupport],
]
--limit
Parameters can limit the number of return values to avoid pressure on the JVM when obtaining large data. The default value is 10.
If you want to accurately locate a specific class instance, you can specify the classloader name or classloader hash, as follows:
vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext
vmtool --action getInstances -c 19469ea2 --className org.springframework.context.ApplicationContext
For the method of obtaining classloader hash, please refer to question 1 above
There is also a nice function of vmtool, which can force GC , which is very effective in some production environments where memory is tight.
vmtool --action forceGc