This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!”

preface

Arthas is Alibaba’s open source Java diagnostic tool, beloved by developers.

Arthas can help you when you have problems such as:

  1. Which JAR is this class loaded from? Why are exceptions related to various classes reported?
  2. Why is the code I changed not executed? Did I not commit? Wrong branch?
  3. You can’t debug online when you encounter a problem, can you only add logs and republish?
  4. There is a problem with the data processing of a user online, but it cannot be debug online or reproduced offline!
  5. Is there a global view of the health of the system?
  6. Is there any way to monitor the real-time state of the JVM?
  7. How to quickly locate the hot spots in the application and generate the flame diagram?
  8. How do I find an instance of a class directly from within the JVM?

Xiaoming opens Artha’s official document, the Arthas User Document – Arthas 3.5.2 Document (aliyun.com)

That’s the first paragraph I read

So I began to read the document in a puffy way

After reading the book, Xiao Ming found that there was no standard solution to the problem

This is not to kill or bury!!

The body of the

Here are my detailed solutions to these eight issues, based on my years of experience with Arthas. Please feel free to comment if you have any questions.

To prepare

Let me give you 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\"]}]";
        // Simulate calling a method over and over again
        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 {
        /** * Name */
        String name;
        /** * Age */
        String age;
        /** * Telephone */
        String telephone;
        /** * Interest list */List<String> interests; }}Copy the code

Here is what the console prints normally

/ 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])]Copy the code

Download and run Arthas, and select a Java process to attach

After attaching is successful, open Google Chrome and enterhttp://127.0.0.1:3658/Open the WebConsole

(It’s not supported in Mac OS Safari.)

The best thing about using the WebConsole is that you can open multiple tabs at once

Question 1: Which JAR is this class loaded from? Why are exceptions related to various classes reported?

This is a problem I often encounter when dealing with various dependency conflicts, where the full names of some classes are identical, and it is not possible to resolve the specific JAR from which the class is loaded by the general method.

Don’t worry. Look at my next solution.

  1. sc

The sc command obfuscates to see if the class containing the keyword is loaded in the current JVM and to get its full name.

Note that the sc -d command is used to get the classLoaderHash, which will be used later.

sc -d *ArthasDemo*
Copy the code

  1. classloader

Use the Classloader to check which JAR package the class file comes from

Use the CLS command to clear the command line, this simple command official document is not found…

Note that the value after classloader -c is the Hash value obtained in the first step above. The class file path is separated by ‘/’ and must end with a.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.
Copy the code

If the class file is from a jar package, you can display the jar package path. For example, the official document gives an example:

$ classloader -c 1b6d3586 -r java/lang/String.classJar file: / Library/Java/JavaVirtualMachines jdk1.8.0 _60. JDK/Contents/Home/jre/lib/rt jar! /java/lang/String.classCopy the code

Question 2: Why is the code I changed not executed? Did I not commit? Wrong branch?

The watch and tt commands are recommended, which are very useful.

Both commands are used to view method calls. The difference is that the watch command prints one method call at a time, while the TT command can create a growing list of calls and then specify one of them to observe.

  1. usewatchCommand to view method invocation. We’re going to look at the convert method call in the ArthasDemo class.

watch com.shockang.study.ArthasDemo convert "{params,target,returnObj}" -f -x 4
Copy the code

Watch is followed by the full class name and method name, and an OGNL expression, -f for observing both normal and abnormal returns, -x for the depth of the property traversal of the output, which defaults to 1,

It is recommended that no brain write 4, which is the maximum traversal depth in my experience

  1. usettCommand to observe method invocation,ttCommand to viewMultiple callsAnd choose one of them to look at, but you can’t look at it if the output is multiple nested, andwatchYou can viewMultilayer nestedResults.

Use tt-t to record the environment scene for each invocation of the current method

tt -t com.shockang.study.ArthasDemo convert
Copy the code

TIMESTAMP indicates the time when the method invocation occurs, COST indicates the duration of the invocation (ms), IS-RET indicates whether the method IS returned normally, IS-exp indicates whether the method IS returned abnormally, and OBJECT indicates the HASH value of the OBJECT

For a specific time slice, you can use the -i parameter followed by the corresponding INDEX number to view the detailed information

The list of interests can be printed in the figure because its toString method is called. If the toString method of the Java.lang. Object class is not overwritten, only the hash value is seen.

  1. How do I know if the code is committed?

Jad –source-only allows you to view the source code.

[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]$
Copy the code

Problem 3: Can’t debug online when you encounter a problem, can you only add logs and re-publish?

Using the watch and tt commands in question 2 above, you can see the method invocation.

In addition, use the re-define command to hot-replace the code on the line, noting that the app will cease to work when it reboots, which works well in emergency situations.

For example, let’s change the code in the method body and add a log print line:

    private List<People> convert(String s) {
        System.out.println(s);
        return JSON.parseArray(s, People.class);
    }
Copy the code

At this point we can hot-replace the running ArthasDemo code with a class file compiled with the new code.

As is obvious from this diagram, the console prints the string despite the fact that there is no logic to print the string s in the source code, because we have hot-replaced the class loaded in the JVM memory (method area).

Problem 4: Online encounter a user’s data processing problem, but online also cannot debug, offline cannot be reproduced!

There is no perfect solution to this problem

See the solutions to problems 2 and 3

You are advised to run the tt command and output the result of the command line to a file. You can run the tt -i command to analyze the abnormal line.

The TEE instruction reads data from the standard input device, outputs its contents to the standard output device, and saves it as a file.

tt -t com.shockang.study.ArthasDemo convert | tee /Users/shockang/Downloads/log
Copy the code

You can also use the monitor command to count the success or failure of method calls.

monitor -c 30 com.shockang.study.ArthasDemo convert | tee /Users/shockang/Downloads/log1
Copy the code

-c Is followed by the statistical period. The default value is 120 seconds

Question 5: Is there a global view of the health of the system?

Using the dashboard command, you can view the real-time data panel of the current system. When running ali-Tomcat, you can display real-time Information about the current Tomcat, such as QPS, RT, error count, thread pool information, and so on.

From the figure you can see the thread situation, memory usage, system parameters and so on.

Question 6: Is there any way to monitor the real-time state of the JVM?

Use the JVM command to view the real-time running status of the JVM.

Question 7: How can I quickly locate hot spots in an application and generate a flame diagram?

The profiler command supports the generation of flame diagrams of application hotspots. Essentially, you take samples over and over again, and then you take those samples and generate a flame pattern.

By default, a CPU flame graph is generated, where event is the CPU and can be specified with the –event parameter. Note that different systems support different events

By default, Arthas uses port 3658, so you can open:http://localhost:3658/arthas-output/View profiler results under arthas-Output directory:

Select an item and click

Question 8: How do YOU find an instance of a class directly from within the JVM?

You can do this using vmTool

This feature is new to Arthas 3.5.1. Refer to the official 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],
]
Copy the code

With the –limit argument, you can limit the number of returned values and avoid straining the JVM when getting too much data. The default value is 10.

To accurately locate a class instance, you can specify a ClassLoader name or a ClassLoader hash, as follows:

vmtool --action getInstances --classLoaderClass org.springframework.boot.loader.LaunchedURLClassLoader --className org.springframework.context.ApplicationContext
Copy the code
vmtool --action getInstances -c 19469ea2 --className org.springframework.context.ApplicationContext
Copy the code

For the method of obtaining the ClassLoader hash, see question 1 above

The VMTool also has a nice feature that can force GC, which works wonders in some production environments where memory is tight.

vmtool --action forceGc
Copy the code