Arthas can't use it after reading the official document? Come in and find out~

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

ArthasIt 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, Arthaswe can help you solve them:

  1. Which jar package is this class loaded from? Why are various types of related Exception reported?
  2. Why is the code I changed not executed? Could it be that I didn't commit? Branching wrong?
  3. If you encounter a problem and cannot debug online, can you only republish it by adding a log?
  4. 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!
  5. Is there a global view into the health of the system?
  6. Is there any way to monitor the real-time running status of the JVM?
  7. How to quickly locate application hotspots and generate flame graphs?
  8. How to find an instance of a class directly from within the JVM?

Xiao Ming opened Arthathe 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.

image.png

Isn't this killing or burying! ! !

image.png

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

Download and run Arthas

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.

  1. sc

Use scthe 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 -dthe command to get classLoaderHash, this value will be used later.

sc -d *ArthasDemo*

sc -d command

  1. classloader

By classloaderviewing which jar package the class file comes from

Use clsthe command to clear the command line, but the official documentation for this simple command cannot be found. . .

classloader -cNote 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 watchthe and ttcommands, which are very easy to use.

These two commands are used to view the method calling process. The difference is that watchthe command prints the calling situation of a method once called, while ttthe command can first generate an ever-increasing calling list, and then specify one of them for observation.

  1. Use watchthe command to view method calls. We want to check the convert method call in the ArthasDemo class.

watch command

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

watchFollowed 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.

  1. Use ttthe command to observe the method call. ttThe 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. watchYou can view the results of multi-level nesting .

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

insert image description here

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
tt -i command

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.

  1. How to judge whether the code has been submitted?

jad --source-onlyYou 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 watchand .tt

In addition, the code on the line can redefinebe 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.

redefine command

insert image description here

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 ttthe 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 -ithe command for in-depth analysis.

teeThe command reads data from the standard input device, outputs its content to the standard output device, and saves it as a file.

tee command

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

In addition, you can also use monitorthe command to count the success and failure of the method call.

insert image description here

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 dashboardthe 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.

insert image description here

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 jvmthe command to view the real-time running status of the JVM.

insert image description here

Question 7: How to quickly locate application hotspots and generate flame graphs?

profilerThe 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

profiler command
By default, arthas uses port 3658, you can open: http://localhost:3658/arthas-output/ to view the profiler results under the arthas-output directory:

profiler directory

select an item click

insert image description here

Question 8: How to find an instance of a class directly from the JVM?

use vmtoolcan 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],
]

--limitParameters 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

Guess you like

Origin blog.csdn.net/Shockang/article/details/117049750