【使用分享】Arthas实战教程,解决Java应用出现的各种问题

本文将结合具体案例,为大家介绍Arthas的常用功能与命令。

一、启动Arthas

Arthas支持在线实例附加,也支持离线命令行启动。这里我们选择在线实例附加:

  1. 下载arthas-boot.jar

    wget https://alibaba.github.io/arthas/arthas-boot.jar
    

    然后使用java -jar执行:

java -jar arthas-boot.jar
  1. 选择目标Java进程,按Enter确认附加:
* [1]: 6492 org.jetbrains.jps.cmdline.Launcher 
* [2]: 21567 
* [3]: 1304 org.apache.catalina.startup.Bootstrap start
* [4]: 22481 

选择要附加的Java进程:3

  1. 就这样,Arthas成功附加到我们的应用中,并打开interactive shell和dashboard

二、查看JVM信息

启动Arthas后,我们首先要熟悉的就是查看JVM信息的相关命令:

dashboard 命令

可以用于展示当前应用程序的实时性能数据和运行状况摘要

dashboard

运行该命令后,会在终端上打印出类似下面这样的实时性能数据和运行状况信息:

  date/time         |    cpu %  | mem usage | req/s | 2xx/s | 3xx/s | 4xx/s | 5xx/s | rt(ms) | status 
2023-04-23 09:40:00 |      1.71 |    93.15% |     0 |     0 |     0 |     0 |     0 |   0.18 | run    
2023-04-23 09:41:00 |      0.98 |    93.15% |     0 |     0 |     0 |     0 |     0 |   0.13 | run    
2023-04-23 09:42:00 |      1.34 |    93.16% |     0 |     0 |     0 |     0 |     0 |   0.17 | run    
2023-04-23 09:43:00 |      1.01 |    93.16% |     0 |     0 |     0 |     0 |     0 |   0.14 | run    
2023-04-23 09:44:00 |      1.17 |    93.16% |     0 |     0 |     0 |     0 |     0 |   0.17 | run    
2023-04-23 09:45:00 |      1.28 |    93.15% |     0 |     0 |     0 |     0 |     0 |   0.16 | run 

上面的输出中,各列含义如下:

  • date/time:时间戳,格式为 YYYY-MM-DD HH:MM:SS
  • cpu %:CPU 使用率百分比;
  • mem usage:内存使用率百分比;
  • req/s:每秒处理请求数;
  • 2xx/s:每秒成功响应 2xx 状态码的请求数;
  • 3xx/s:每秒成功响应 3xx 状态码的请求数;
  • 4xx/s:每秒成功响应 4xx 状态码的请求数;
  • 5xx/s:每秒成功响应 5xx 状态码的请求数;
  • rt(ms):平均响应时间(毫秒);
  • status:当前应用程序运行状态。

其中 status 列有以下几种可能的取值:

  • run:应用程序正在运行;
  • down:应用程序已经停止。

此外,dashboard 命令还会在终端上显示以下统计信息:

  • cpu:当前应用程序 CPU 的使用情况;
  • memory:当前应用程序内存的使用情况;
  • thread:当前应用程序线程池的使用情况;
  • gc:当前应用程序垃圾回收的情况。

这些统计信息将占用屏幕上的一部分空间,并且每隔一段时间就会更新一次。

除了以上列出的信息之外,dashboard 命令还允许你使用键盘的方向键来滚动屏幕,以查看更早之前的数据。同时,你也可以使用键盘上的 q 键来退出 dashboard 视图

thread 命令

thread 命令可以用于展示应用程序中所有线程的当前状态信息。以下是 thread 命令的正确用法:

thread

运行该命令后,会在终端上打印出类似下面这样的所有线程的状态信息:

"Attach Listener" daemon prio=9 tid=0x7f57bc000800 nid=0x116f waiting on condition [0x0000000000000000]
   java.lang.Thread.State: RUNNABLE

"pool-1-thread-1" prio=5 tid=0x7f57c006c000 nid=0x1098 runnable [0x7f57d32e3000]
   java.lang.Thread.State: RUNNABLE
        at com.alibaba.arthas.samples.thread.ThreadSample$MyThread.run(ThreadSample.java:25)

"main" prio=5 tid=0x7f57bc000800 nid=0x1054 in Object.wait() [0x7f57d3fff000]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        at java.lang.Object.wait(Object.java:502)
        at com.alibaba.arthas.samples.thread.ThreadSample.main(ThreadSample.java:10)

上面的输出中,每个线程的状态信息包括了以下几个部分:

  • 线程名称(用双引号括起来);
  • 线程调度优先级(prio);
  • 线程 ID (tid);
  • 线程进程内唯一标识符(nid);
  • 等待条件(waiting on condition),如果线程正在等待某个条件,则会显示该条件;
  • 线程当前所处状态(Thread.State);
  • 如果是 Java 应用程序线程,还会显示线程当前执行的方法和源代码行号。

其中,Thread.State 列是最为重要的一列,它表示了线程当前的状态。Java 线程有以下几种状态:

  • NEW:尚未启动的线程的状态。
  • RUNNABLE:正在执行中的线程的状态。
  • BLOCKED:因为某些原因无法继续执行的线程的状态(例如等待获取某个锁)。
  • WAITING:因为某些条件的发生而无法继续执行的线程的状态。
  • TIMED_WAITING:与 WAITING 状态类似,但是可以设置超时时间,在时间到达之前无法继续执行的线程的状态。
  • TERMINATED:已经执行完毕的线程的状态。

除了以上列出的信息之外,thread 命令还允许你使用键盘的方向键来滚动屏幕,以查看更多线程。同时,你也可以使用键盘上的 q 键来退出 thread 视图。

JVM命令

jvm 命令可以帮助你查看和管理当前应用程序的 JVM 状态和配置参数。以下是 jvm 命令的正确用法:

jvm

运行该命令后,会在终端上打印出如下所示的 JVM 相关信息:

PID: 1234
Java Home: /usr/local/java/jdk1.8.0_131/jre
Java Version: 1.8.0_131
Java VM Name: Java HotSpot(TM) 64-Bit Server VM
Java VM Vendor: Oracle Corporation
Java Options: -XX:+HeapDumpOnOutOfMemoryError -Xmx512m -Xms256m

上面的输出中,各列含义如下:

  • PID:当前应用程序的进程 ID;
  • Java Home:当前应用程序使用的 JDK/JRE 的安装路径;
  • Java Version:当前应用程序所使用的 JDK/JRE 版本号;
  • Java VM Name:JVM 实现商名称;
  • Java VM Vendor:JVM 实现商名称;
  • Java Options:当前应用程序启动时设置的 JVM 参数。

其中,Java Options 列显示了当前应用程序启动时指定的一些 JVM 参数。这些参数通常指定了 JVM 堆大小, GC 策略,堆外内存大小,日志级别等等。你可以根据实际需要调整这些参数来优化应用程序的性能和资源利用率。

除了以上列出的信息之外,jvm 命令还支持一些子命令,例如 monitordumpprint 等等,用于监控 JVM 运行状况、生成堆转储文件、打印内存映射信息等等。你可以在 jvm 命令后添加这些子命令来执行相应的操作。

sysprop命令

sysprop 命令可以用于查看 Java 系统属性。以下是 sysprop 命令的正确用法:

sysprop

运行该命令后,会在终端上打印出所有 Java 系统属性及其对应的值,类似下面这样:

java.io.tmpdir = /tmp
java.class.path = /usr/local/tomcat/lib/servlet-api.jar:/usr/local/tomcat/lib/jsp-api.jar:/usr/local/tomcat/lib/tomcat-juli.jar
java.home = /usr/local/java/jdk1.8.0_131/jre
java.vm.name = Java HotSpot(TM) 64-Bit Server VM
...

上面的输出中,每个 Java 系统属性和其对应的值都表示为一行输出,形如 property_name = property_value

Java 系统属性是一些由 JVM 预定义的变量,它们通常用于控制 JVM 和应用程序的行为。例如,java.home 属性表示当前使用的 JRE/JDK 安装路径,java.io.tmpdir 属性表示临时文件目录位置,java.class.path 属性表示类路径等等。你可以根据实际需要查询这些属性的值,并根据情况调整应用程序或 JVM 的配置参数,以达到更好的性能或功能需求。

除了以上列出的信息之外,sysprop 命令还支持一些选项,例如 -p 选项可以用于查找具有指定前缀的系统属性,-e 选项可以用于查找具有指定后缀的系统属性等等。你可以在命令行中加上相应的选项来执行更复杂的查询操作。

sysenv命令

sysenv 命令可以用于查看操作系统环境变量。以下是 sysenv 命令的正确用法:

sysenv

运行该命令后,会在终端上打印出所有环境变量及其对应的值,类似下面这样:

TERM_PROGRAM=Apple_Terminal
SHELL=/bin/bash
TERM=xterm-256color
TMPDIR=/var/folders/67/0__r6w1d6vq3s7s48hrtj1200000gn/T/
....

上面的输出中,每个环境变量和其对应的值都表示为一行输出,形如 variable_name=value

操作系统环境变量是一些由操作系统预定义的变量,它们通常用于控制操作系统和应用程序的行为。例如,PATH 环境变量表示可执行程序的搜索路径,HOME 环境变量表示当前用户的主目录路径等等。你可以根据实际需要查询这些环境变量的值,并根据情况调整应用程序或操作系统的配置参数,以达到更好的性能或功能需求。

除了以上列出的信息之外,sysenv 命令还支持一些选项,例如 -p 选项可以用于查找具有指定前缀的环境变量,-e 选项可以用于查找具有指定后缀的环境变量等等。你可以在命令行中加上相应的选项来执行更复杂的查询操作。

三、检测线程问题

thread -b 命令

thread -b 命令可以用于展示当前应用程序中所有线程的堆栈信息,并以火焰图的形式进行显示。以下是 thread -b 命令的正确用法:

thread -b

运行该命令后,会在终端上打印出如下所示的火焰图:

    main
      |-com.example.demo.MyController.index(MyController.java:11)
      |  |-com.example.demo.MyService.process(MyService.java:26)
      |  |  |-com.example.demo.MyDao.query(MyDao.java:32)
      |  |  |  |-java.sql.PreparedStatement.executeQuery(PreparedStatement.java:-1)
      |  |  |  |   |-org.apache.tomcat.jdbc.pool.interceptor.StatementDecorator$StatementProxy.executeQuery(StatementDecorator.java:212)
      |  |  |  |   |-org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:63)
      |  |  |  |   |  |-org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79)
      |  |  |  |   |  |   |-org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63)
      |  |  |  |   |  |   |  |-org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)
      |  |  |  |   |  |   |  |-org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
      |  |  |  |   |  |   |  |  |-org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
      |  |  |  |   |  |   |  |  |-org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:73)
      |  |  |  |   |  |   |  |     |-org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324)
      |  |  |  |   |  |   |  |-com.example.demo.MyMapper.query(MyMapper.java:38)
      |  |  |-java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
      |  |  |-java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
      |  |  |-java.lang.Thread.run(Thread.java:748)
      |  |-sun.nio.ch.EPollArrayWrapper.epollWait(Native Method)
      |  |-sun.nio.ch.EPollArrayWrapper.poll(EPollArrayWrapper.java:269)
      |  |-sun.nio.ch.EPollSelectorImpl.doSelect(EPollSelectorImpl.java:92)

上面的输出中,每个线程的堆栈信息都被转化为火焰图的形式进行显示。在火焰图中,每一行表示一个调用栈帧,每个矩形表示一个方法调用,矩形的宽度表示该方法在整个堆栈中的占比,颜色越深表示该方法的执行时间越长。

通过观察火焰图,你可以快速定位到代码中执行时间最长的部分,并针对这些部分进行优化和调整。例如,上面的火焰图中可以看出 MyDao.query 方法所占用的时间较长,你可以针对这个方法进行性能优化。

除了以上列出的信息之外,thread -b 命令还允许你使用键盘的方向键来滚动屏幕,以查看更早之前的堆栈信息。同时,你也可以使用键盘上的 q 键来退出火焰图视图。

thread -n 命令

thread -n 命令可以用于展示当前应用程序中所有线程的简要信息,包括线程 ID、状态、名称等。以下是 thread -n 命令的正确用法:

thread -n

运行该命令后,会在终端上打印出如下所示的线程列表:

ID     STATE         NAME
1      RUNNABLE      main
2      WAITING       Thread-1
3      TIMED_WAITING Thread-2
4      BLOCKED       Thread-3
5      RUNNABLE      Thread-4
6      TERMINATED    Thread-5
...

上面的输出中,每行表示一个线程的简要信息,分别包括线程 ID、状态和名称等。其中,各列的含义如下:

  • ID:线程 ID;
  • STATE:线程状态;
  • NAME:线程名称。

线程状态有多种可能,包括 RUNNABLE(可运行状态)、WAITING(等待状态)、TIMED_WAITING(超时等待状态)和 BLOCKED(阻塞状态)等。通过查看线程状态,你可以了解到线程当前的执行情况和所处状态,以便进一步进行性能和调试优化。

除了以上列出的信息之外,thread -n 命令还支持一些选项,例如 -p 选项可以用于只显示指定线程 ID 的信息,-s 选项可以用于按照指定的列排序线程列表等等。你可以在命令行中加上相应的选项来执行更复杂的操作。

trace 命令

以下是使用trace命令监控方法调用并输出方法执行时的信息。

假设我们要监控一个Spring Boot应用中的某个Controller方法,可以执行以下命令:

trace com.example.controller.UserController getUserList

这个命令的含义是:追踪com.example.controller.UserController类中名为getUserList的方法,并在每次该方法被调用时输出一些运行时的信息。

当我们访问该Controller的/user/list接口时,Arthas会自动拦截该方法的调用,并输出类似下面的结果:

Press Ctrl+C to abort.
ts=2023-04-23 17:44:42; thread_name=http-nio-8080-exec-1; [cost=4ms]com.example.controller.UserController.getUserList();
    public java.util.List<com.example.entity.User> com.example.controller.UserController.getUserList() throws java.lang.Exception : 0ms
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:566)
...(省略部分输出)

这个输出表示该方法最后一次被调用的时间(timestamp)、调用线程名(thread_name)、方法的执行耗时(cost)以及方法执行的详细调用栈。其中cost表示方法执行的耗时,单位是毫秒。

需要注意的是,trace命令会对目标方法进行动态修改,因此可能会带来一些性能损失。在生产环境中不建议频繁使用该命令,以免影响应用程序的性能。

stack命令

stack 命令可以用来查看指定 Java 进程中某个线程的调用栈信息。

命令格式为:

stack [options] <thread-id>

其中 <thread-id> 是需要查看调用栈的线程的 ID。

可以使用的选项包括:

  • -n <num>:指定要显示的栈帧数,默认为10。
  • -d:输出详细的调试信息。
  • --exclude:指定要排除的包或类名,多个用逗号分隔。
  • --exclude-re:指定要排除的正则表达式,对应的包或类名将被排除。

例如,如果我想查看当前进程中 ID 为 1 的线程的调用栈信息,可以执行以下命令:

$ stack 1

执行结果会输出该线程的调用栈信息,每行信息包含以下几个部分:

  • at:表示该栈帧所在的方法调用链位置。
  • <class>.<method>(<args>):表示该栈帧所在的方法的名称和参数列表。
  • Native Method 或者 Unknown Source:表示该栈帧所在方法的源码位置。如果是 Native Method,则表明该方法是由本地代码实现的;如果是 Unknown Source,则表明该方法没有源码信息可用。
  • line: <line-number>:表示该栈帧所在的源码行号。如果该方法没有源码信息,则忽略该部分。

下面是一个示例输出:

$ stack 1
Thread 1: 
    at com.example.demo.DemoController.handleRequest(DemoController.java:13)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)    
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
...

这里输出了线程 1 的调用栈信息,包括每个栈帧所在方法的名称和参数列表,以及源码位置(如果有)。注意,第一行 "Thread 1:" 是为了区分不同线程的输出,在只查看单个线程时可能会省略

jad 命令

jad 命令可以将指定类反编译为 Java 源代码,并输出到控制台。它的用法如下:

jad 类名

其中 类名 参数指定需要反编译的类的全限定名。

例如,我们想要反编译 Spring Framework 的 org.springframework.web.servlet.DispatcherServlet 类,可以使用以下命令:

jad org.springframework.web.servlet.DispatcherServlet

执行上述命令后,Arthas 会输出该类的反编译结果,包括类的定义、成员变量和方法等信息。输出的内容非常详细,包括每个方法的访问修饰符、返回值类型、参数列表、异常抛出列表以及方法体等信息。以下是可能的输出示例:

ClassLoader:
+-sun.misc.Launcher$AppClassLoader@1f96302a

Location:
+-/Library/Tomcat/apache-tomcat-9.0.27/webapps/demo/WEB-INF/lib/spring-webmvc-5.3.8.jar
-!org.springframework.web.servlet.DispatcherServlet

Decompiled with Fernflower-Jetbrains decompiler.

// package org.springframework.web.servlet;

public class DispatcherServlet extends FrameworkServlet {
    // ...

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // ...
    }

    // ...
}

在这个输出中,我们可以看到该类所处的 ClassLoader 和所在的 JAR 包路径,以及通过 Fernflower 反编译器反编译得到的类定义和方法实现。其中,类定义部分被注释为 // package org.springframework.web.servlet;,方法部分则包括了每个方法的代码实现。

四、性能监控与调优

monitor命令

monitor 命令可以监视指定方法的调用情况,并输出相关统计信息。它的用法如下:

monitor [options] className methodName

其中,className 参数指定要监视的类的全限定名,methodName 参数指定要监视的方法名。options 参数是可选的,可以用于控制监视器的行为。

以下是一些常见的 monitor 命令选项:

  • -c: 统计调用次数。
  • -n: 指定最大统计次数。
  • -t: 指定统计时间间隔,单位是毫秒。
  • -b: 打印调用堆栈跟踪信息。

例如,我们想要监视 Spring Framework 的 org.springframework.web.servlet.DispatcherServlet 类中的 doDispatch 方法的调用情况,可以使用以下命令:

monitor -c 10 -t 1000 -b org.springframework.web.servlet.DispatcherServlet doDispatch

执行上述命令后,Arthas 会输出该方法的调用情况统计信息,包括调用次数、平均响应时间、最小响应时间、最大响应时间等指标。如果指定了 -b 选项,则还会打印每次调用的调用堆栈跟踪信息。

以下是可能的输出示例:

Monitoring org.springframework.web.servlet.DispatcherServlet.doDispatch(int,javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse) for 10 times, interval: 1000ms...
Press Ctrl+C to stop
Started after 1ms. Cost per invocations: AVG(0ms), MIN(0ms), MAX(0ms).
Count:      10  Average:    2ms  Min:    1ms  Max:    4ms
Thread Count: 1  Thread Waiting Count: 0  Total Time: 22ms

Stack Trace:
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057)
    ...


Stopped after 11078ms, success rate: 100.00%

在这个输出中,我们可以看到监视器的基本信息,包括监视的方法名、监视次数和统计时间间隔等。下面是具体的统计信息:

  • Count: 方法调用次数。
  • Average: 平均响应时间。
  • Min: 最小响应时间。
  • Max: 最大响应时间。

此外,我们还可以看到线程数量和等待线程数量的统计信息,以及总共的执行时间。最后,如果指定了 -b 选项,则会在输出末尾打印每次调用的调用堆栈跟踪信息

watch 命令

watch 命令可以监视指定表达式的值,并在其发生变化时输出相关信息。它的用法如下:

watch [options] expression

其中,expression 参数是需要监视的表达式。options 参数是可选的,可以用于控制监视器的行为。

以下是一些常见的 watch 命令选项:

  • -x: 将监视器设为一次性的,即只监视一次变化。
  • -n: 指定最大监视次数。

例如,我们想要监视变量 i 的值,在其改变时输出信息,可以使用以下命令:

watch i

执行上述命令后,Arthas 会在变量 i 的值发生变化时输出相关信息。

以下是可能的输出示例:

2021-08-09 21:18:30
Watching i
Press Ctrl+C to abort.
[Cost    ] : 3.794 ms
[Thread  ] : main
[Location] : jademo.demo.MainController.lambda$watch$0(MainController.java:23)
i: 10 -> 11

2021-08-09 21:18:31
Watching i
Press Ctrl+C to abort.
[Cost    ] : 1.192 ms
[Thread  ] : main
[Location] : jademo.demo.MainController.lambda$watch$0(MainController.java:23)
i: 11 -> 12

在这个输出中,我们可以看到监视器每秒钟检查一次变量 i 的值,并在其发生变化时输出相关信息。输出中包括时间戳、监视的表达式、执行时间、当前线程、触发位置和变量的旧值和新值等信息。由于是连续输出的,所以可以实时观察变量值的变化情况。

heapdump 命令

heapdump 命令可以生成 Java 应用程序的内存快照,并将其保存到指定文件中。它的用法如下:

heapdump <file>

其中,file 参数是要保存内存快照的文件路径。

例如,我们想要生成一个名为 mydump.hprof 的内存快照文件,可以使用以下命令:

heapdump /path/to/mydump.hprof

执行上述命令后,Arthas 会在后台线程中生成并保存内存快照,不会阻塞当前线程。生成过程可能需要一些时间,具体时间取决于 JVM 进程的内存大小和负载情况。生成完毕后,Arthas 会输出相关提示信息。

以下是可能的输出示例:

Dumping heap to /path/to/mydump.hprof...
Heap dump file created

在这个输出中,我们可以看到提示信息,表示内存快照已经成功生成。根据应用程序的实际情况和 JVM 进程的内存大小,生成的内存快照文件可能很大,通常几百 MB 到几 GB 不等。我们可以使用工具如 Eclipse Memory Analyzer 或 jhat 等来分析内存快照文件,以了解应用程序的内存使用情况。

配合 jhat 生成与解析堆快照定位内存问题

redefine命令

redefine 命令可以动态替换 Java 应用程序中的类定义,并在不重启 JVM 的情况下生效。它的用法如下:

redefine <class-pattern> <jad-file>

其中,class-pattern 参数是需要重定义的类名模式,支持通配符 * 和正则表达式;jad-file 参数是包含新类定义的 Java 源代码文件路径或者已编译的 Class 文件路径。

例如,我们想要将 Spring Framework 中的 org.springframework.web.servlet.DispatcherServlet 类进行修改,并且能够即时生效,可以使用以下命令:

  1. 使用 jad 命令反编译该类:
jad org.springframework.web.servlet.DispatcherServlet
  1. 修改反编译得到的源代码,并将其保存为新的 Java 源代码文件 MyDispatcherServlet.java
  2. 使用 javac 命令编译源代码文件,生成对应的 Class 文件:
javac MyDispatcherServlet.java
  1. 使用 redefine 命令动态替换原来的类定义:
redefine org.springframework.web.servlet.DispatcherServlet /path/to/MyDispatcherServlet.class

执行上述命令后,Arthas 会重新加载指定类的新定义,并使其生效。由于此操作可能会破坏应用程序的正确性,因此建议谨慎使用。

需要注意的是,redefine 命令只能替换没有被虚拟机加载的类,也就是说,如果某个类已经被加载了,则需要先卸载它,才能重新加载新的定义。另外,在 JDK 9 及以上版本中,由于引入了模块化系统,使用 redefine 命令可能会受到一定的限制。

总结

通过上述简单的功能介绍,相信您对Arthas的强大功能已有初步了解。它可以应对我们日常开发与运维过程中绝大部分的问题,而无需重启服务。我将在后续的系列文章中,结合具体的案例来为大家详细地讲解Arthas的各项功能与命令,学会运用Arthas解决各种Java应用问题

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容