你是否在项目中会碰到以下一些问题:
- 在代码中打印各种日志来排查,比如方法的入参,出参,及在方法体中打印日志判断走哪行代码
- 还有你觉得代码没问题,可是运行出现却是以前的bug,感觉代码没修改,或者别人把你修改好之前的代码部署上去了,你想要看线上部署的是不是你修改的最新代码,把包从服务器上下载下来然后再反编译查看
- 有些接口请求很慢,你想知道这个接口的方法调用链中耗时时间,你以前是不是通过切面去打印每个方法的耗时时间,修改代码,重新部署
- 当进程CPU飙高或者占用内存较大,你用top命令查看,然后top -H -p x,把十进制转成16进制,然后jstack x | grep -A 10 y命令排查,会觉得有点麻烦
- 当本地程序运行正常,线上代码运行不正常,你可能需要优化一个class几行代码,在线上看是否会运行正常,重新打包部署,会觉得有点麻烦
其实阿里的线上排查工具arthas就可以解决上述问题
下载地址:https://alibaba.github.io/arthas/arthas-boot.jar
直接执行命令:
java -jar arthas-boot.jar
如果出现中文乱码,需要添加参数 -Dfile.encoding=UTF-8 :
java -Dfile.encoding=UTF-8 -jar arthas-boot.jar
直接输入你要连接的进程号:如 4
进入arthas交互界面
现在根据以下代码来进行测试:
package com.htf.smm.controller;
import com.htf.smm.service.SmmIndexSyncService;
import com.htf.smm.service.impl.TestServiceOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.repository.query.Param;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Objects;
@RestController
@RequestMapping("/smm")
public class SmmController {
@Autowired
private TestServiceOne testServiceOne;
@RequestMapping("/ycTest")
public void ycTest(Long time) {
System.out.println("执行开始,"+time);
Other other = new Other();
other.setInfo("其他");
Coordinate coordinate = new Coordinate();
coordinate.setX(1);
coordinate.setY(2);
coordinate.setOther(other);
Address address = new Address();
address.setAddr("昌北");
address.setCoordinate(coordinate);
School school = new School();
school.setName("华东交大");
school.setAddress(address);
ParamEntiry paramEntiry = new ParamEntiry();
paramEntiry.setName("yc");
paramEntiry.setAge(32);
paramEntiry.setSchool(school);
test(paramEntiry);
System.out.println("执行完毕");
}
public ReturnEntity test(ParamEntiry paramEntiry){
ReturnEntity returnEntity = new ReturnEntity();
Other other = new Other();
other.setInfo("其他");
Coordinate coordinate = new Coordinate();
coordinate.setX(1);
coordinate.setY(2);
coordinate.setOther(other);
Address address = new Address();
address.setAddr("昌北");
address.setCoordinate(coordinate);
School school = new School();
school.setName("华东交大");
school.setAddress(address);
returnEntity.setSchool(school);
return returnEntity;
}
}
package com.htf.smm.controller;
import lombok.Data;
@Data
public class ParamEntiry {
private String name;
private Integer age;
private School school;
}
@Data
class School{
private String name;
private Address address;
}
@Data
class Address{
private String addr;
private Coordinate coordinate;
}
@Data
class Coordinate{
private int x;
private int y;
private Other other;
}
@Data
class Other{
private String info;
}
@Data
public class ReturnEntity {
private String name;
private Integer age;
private School school;
}
package com.htf.smm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestServiceOne {
private String serviceName = "one";
@Autowired
private TestServiceTwo testServiceTwo;
}
package com.htf.smm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestServiceTwo {
private String serviceName = "two";
@Autowired
private TestServiceThree testServiceThree;
}
package com.htf.smm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestServiceThree {
private String serviceName = "three";
@Autowired
private TestServiceFour testServiceFour;
}
package com.htf.smm.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TestServiceFour {
private String serviceName = "four";
@Autowired
private TestServiceFive testServiceFive;
}
下面来介绍常用的几个命令,watch,trace,stack ,jad,redefine ,thrad
watch命令
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 函数名表达式匹配 |
express | 观察表达式,默认值:{params, target, returnObj} |
condition-express | 条件表达式 |
[b] | 在函数调用之前观察 |
[e] | 在函数异常之后观察 |
[s] | 在函数返回之后观察 |
[f] | 在函数结束之后(正常返回和异常返回)观察 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[x:] | 指定输出结果的属性遍历深度,默认为 1,最大值是 4 |
[arthas@9388]$ watch com.htf.smm.controller.SmmController test
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 27 ms, listenerId: 5
method=com.htf.smm.controller.SmmController.test location=AtExit
ts=2023-03-01 15:11:33; [cost=0.0424ms] result=@ArrayList[
@Object[][isEmpty=false;size=1],
@SmmController[com.htf.smm.controller.SmmController@59fe5960],
@ReturnEntity[ReturnEntity(name=null, age=null, school=School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他)))))],
]
默认返回params,target,returnObj({params, target, returnObj})深度为1(-x 1),且
在函数结束之后(正常返回和异常返回)(
-f)
观察,即等于下面这个命令
[arthas@9388]$ watch com.htf.smm.controller.SmmController test "{params, target, returnObj}" -x 1 -f
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 7
method=com.htf.smm.controller.SmmController.test location=AtExit
ts=2023-03-01 15:44:01; [cost=0.0398ms] result=@ArrayList[
@Object[][isEmpty=false;size=1],
@SmmController[com.htf.smm.controller.SmmController@59fe5960],
@ReturnEntity[ReturnEntity(name=null, age=null, school=School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他)))))],
]
@Object[][isEmpty=false;size=1] 为params,为什么是个数组呢?因为参数可能有多个
@SmmController[com.htf.smm.controller.SmmController@59fe5960] 为当前对象
@ReturnEntity[ReturnEntity(name=null, age=null, school=School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他)))))] 为returnObj
location=AtExit 为在函数结束之后正常返回观察
重要参数-x,默认为1,但是当参数和当前对象的属性有对象引用的时候,我们就需要用到-x,如上命令执行 @SmmController[com.htf.smm.controller.SmmController@59fe5960] 我们无法查看到当前对象内部有什么属性,@Object[][isEmpty=false;size=1]当前参数的具体值
我们设置-x 2试试
[arthas@9388]$ watch com.htf.smm.controller.SmmController test "{params, target, returnObj}" -x 2 -f
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 29 ms, listenerId: 14
method=com.htf.smm.controller.SmmController.test location=AtExit
ts=2023-03-01 16:01:39; [cost=0.0249ms] result=@ArrayList[
@Object[][
@ParamEntiry[ParamEntiry(name=yc, age=32, school=School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他)))))],
],
@SmmController[
testServiceOne=@TestServiceOne[com.htf.smm.service.impl.TestServiceOne@55111d28],
],
@ReturnEntity[
name=null,
age=null,
school=@School[School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他))))],
],
]
上述所示,就把参数1对应的对象展示出来了,把当前对象中的对象引用展示出来了,把返回对象的引用给展示出来了
注意:-x的最大值为4
重要参数-n,默认是无限次,当线上执行这个接口比较频繁,我们用运维工具可能会频繁去监听打印这个方法相关的信息,很耗服务器资源,而且影响接口响应耗时的时间,当我们为了排查问题,只要获取到一次监听的时候,就可以加-n参数,-n 1表示只执行两次,执行1次后,就会自动退出监听
[arthas@9388]$ watch com.htf.smm.controller.SmmController test "{params, target, returnObj}" -x 2 -f -n 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 30 ms, listenerId: 15
method=com.htf.smm.controller.SmmController.test location=AtExit
ts=2023-03-01 16:12:51; [cost=0.0357ms] result=@ArrayList[
@Object[][
@ParamEntiry[ParamEntiry(name=yc, age=32, school=School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他)))))],
],
@SmmController[
testServiceOne=@TestServiceOne[com.htf.smm.service.impl.TestServiceOne@55111d28],
],
@ReturnEntity[
name=null,
age=null,
school=@School[School(name=华东交大, address=Address(addr=昌北, coordinate=Coordinate(x=1, y=2, other=Other(info=其他))))],
],
]
Command execution times exceed limit: 1, so command will exit. You can set it with -n option.
最后一行Command execution times exceed limit: 1, so command will exit. You can set it with -n option.表示执行次数限制为1次,可以通过-n来设置执行的次数
trace命令
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[n:] | 命令执行次数 |
#cost | 方法执行耗时 |
根据耗时"#cost>0"大小匹配如下,耗时是以s为单位的
[arthas@9388]$ trace com.htf.smm.controller.SmmController ycTest "#cost>0"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 36 ms, listenerId: 27
`---ts=2023-03-02 09:54:37;thread_name=http-nio-8080-exec-2;id=4f;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1aa6e3c0
`---[0.3154ms] com.htf.smm.controller.SmmController:ycTest()
+---[3.01% 0.0095ms ] com.htf.smm.controller.Other:<init>() #31
+---[1.49% 0.0047ms ] com.htf.smm.controller.Other:setInfo() #32
+---[1.81% 0.0057ms ] com.htf.smm.controller.Coordinate:<init>() #33
+---[1.55% 0.0049ms ] com.htf.smm.controller.Coordinate:setX() #34
+---[1.20% 0.0038ms ] com.htf.smm.controller.Coordinate:setY() #35
+---[1.30% 0.0041ms ] com.htf.smm.controller.Coordinate:setOther() #36
+---[1.30% 0.0041ms ] com.htf.smm.controller.Address:<init>() #37
+---[1.17% 0.0037ms ] com.htf.smm.controller.Address:setAddr() #38
+---[1.24% 0.0039ms ] com.htf.smm.controller.Address:setCoordinate() #39
+---[1.17% 0.0037ms ] com.htf.smm.controller.School:<init>() #40
+---[1.33% 0.0042ms ] com.htf.smm.controller.School:setName() #41
+---[1.33% 0.0042ms ] com.htf.smm.controller.School:setAddress() #42
+---[1.24% 0.0039ms ] com.htf.smm.controller.ParamEntiry:<init>() #43
+---[1.14% 0.0036ms ] com.htf.smm.controller.ParamEntiry:setName() #44
+---[1.43% 0.0045ms ] com.htf.smm.controller.ParamEntiry:setAge() #45
+---[1.24% 0.0039ms ] com.htf.smm.controller.ParamEntiry:setSchool() #46
`---[3.01% 0.0095ms ] com.htf.smm.controller.SmmController:test() #47
stack命令
参数名称 | 参数说明 |
---|---|
class-pattern | 类名表达式匹配 |
method-pattern | 方法名表达式匹配 |
condition-express | 条件表达式 |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
[n:] | 执行次数限制(stack,watch,trace命令用法一致) |
根据参数值"params[0].name=='yc'"匹配,用法如下:
[arthas@9388]$ stack com.htf.smm.controller.SmmController test "params[0].name=='yc'"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 28 ms, listenerId: 37
ts=2023-03-02 10:16:57;thread_name=http-nio-8080-exec-4;id=51;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1aa6e3c0
@com.htf.smm.controller.SmmController.test()
at com.htf.smm.controller.SmmController.ycTest(SmmController.java:47)
at sun.reflect.GeneratedMethodAccessor55.invoke(null:-1)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)
注意:stack命令和trace命令参数值匹配和耗时大小匹配可以联合使用,如下:
[arthas@9388]$ stack com.htf.smm.controller.SmmController test "params[0].name=='yc'" "#cost>0"
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 38 ms, listenerId: 38
ts=2023-03-02 10:23:37;thread_name=http-nio-8080-exec-6;id=53;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@1aa6e3c0
@com.htf.smm.controller.SmmController.test()
at com.htf.smm.controller.SmmController.ycTest(SmmController.java:47)
at sun.reflect.GeneratedMethodAccessor55.invoke(null:-1)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)
jad命令
lass-pattern | 类名表达式匹配 |
[c:] | 类所属 ClassLoader 的 hashcode |
[classLoaderClass:] | 指定执行表达式的 ClassLoader 的 class name |
[E] | 开启正则表达式匹配,默认为通配符匹配 |
反编译类jad 类路径:
[arthas@9388]$ jad com.htf.smm.controller.SmmController
ClassLoader:
+-sun.misc.Launcher$AppClassLoader@58644d46
+-sun.misc.Launcher$ExtClassLoader@71c7db30
Location:
/E:/code/htf/htf-parent/htf-damp-parent/htf-damp-smm/target/classes/
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.htf.smm.controller.Address
* com.htf.smm.controller.Coordinate
* com.htf.smm.controller.Other
* com.htf.smm.controller.ParamEntiry
* com.htf.smm.controller.ReturnEntity
* com.htf.smm.controller.School
* com.htf.smm.service.impl.TestServiceOne
*/
package com.htf.smm.controller;
import com.htf.smm.controller.Address;
import com.htf.smm.controller.Coordinate;
import com.htf.smm.controller.Other;
import com.htf.smm.controller.ParamEntiry;
import com.htf.smm.controller.ReturnEntity;
import com.htf.smm.controller.School;
import com.htf.smm.service.impl.TestServiceOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value={"/smm"})
public class SmmController {
@Autowired
private TestServiceOne testServiceOne;
public ReturnEntity test(ParamEntiry paramEntiry) {
ReturnEntity returnEntity = new ReturnEntity();
Other other = new Other();
/*54*/ other.setInfo("其他");
Coordinate coordinate = new Coordinate();
/*56*/ coordinate.setX(1);
/*57*/ coordinate.setY(2);
/*58*/ coordinate.setOther(other);
Address address = new Address();
/*60*/ address.setAddr("昌北");
/*61*/ address.setCoordinate(coordinate);
School school = new School();
/*63*/ school.setName("华东交大");
/*64*/ school.setAddress(address);
/*65*/ returnEntity.setSchool(school);
/*66*/ return returnEntity;
}
@RequestMapping(value={"/ycTest"})
public void ycTest(Long time) throws InterruptedException {
/*30*/ System.out.println("执行开始," + time);
Other other = new Other();
/*32*/ other.setInfo("其他");
Coordinate coordinate = new Coordinate();
/*34*/ coordinate.setX(1);
/*35*/ coordinate.setY(2);
/*36*/ coordinate.setOther(other);
Address address = new Address();
/*38*/ address.setAddr("昌北");
/*39*/ address.setCoordinate(coordinate);
School school = new School();
/*41*/ school.setName("华东交大");
/*42*/ school.setAddress(address);
ParamEntiry paramEntiry = new ParamEntiry();
/*44*/ paramEntiry.setName("yc");
/*45*/ paramEntiry.setAge(Integer.valueOf(32));
/*46*/ paramEntiry.setSchool(school);
/*47*/ this.test(paramEntiry);
/*48*/ System.out.println("执行完毕");
}
}
Affect(row-cnt:1) cost in 357 ms.
其中有ClassLoader和Location信息,如果把他去掉,加 --source-only 参数,如下所示:
[arthas@9388]$ jad com.htf.smm.controller.SmmController --source-only
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.htf.smm.controller.Address
* com.htf.smm.controller.Coordinate
* com.htf.smm.controller.Other
* com.htf.smm.controller.ParamEntiry
* com.htf.smm.controller.ReturnEntity
* com.htf.smm.controller.School
* com.htf.smm.service.impl.TestServiceOne
*/
package com.htf.smm.controller;
import com.htf.smm.controller.Address;
import com.htf.smm.controller.Coordinate;
import com.htf.smm.controller.Other;
import com.htf.smm.controller.ParamEntiry;
import com.htf.smm.controller.ReturnEntity;
import com.htf.smm.controller.School;
import com.htf.smm.service.impl.TestServiceOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value={"/smm"})
public class SmmController {
@Autowired
private TestServiceOne testServiceOne;
public ReturnEntity test(ParamEntiry paramEntiry) {
ReturnEntity returnEntity = new ReturnEntity();
Other other = new Other();
/*54*/ other.setInfo("其他");
Coordinate coordinate = new Coordinate();
/*56*/ coordinate.setX(1);
/*57*/ coordinate.setY(2);
/*58*/ coordinate.setOther(other);
Address address = new Address();
/*60*/ address.setAddr("昌北");
/*61*/ address.setCoordinate(coordinate);
School school = new School();
/*63*/ school.setName("华东交大");
/*64*/ school.setAddress(address);
/*65*/ returnEntity.setSchool(school);
/*66*/ return returnEntity;
}
@RequestMapping(value={"/ycTest"})
public void ycTest(Long time) throws InterruptedException {
/*30*/ System.out.println("执行开始," + time);
Other other = new Other();
/*32*/ other.setInfo("其他");
Coordinate coordinate = new Coordinate();
/*34*/ coordinate.setX(1);
/*35*/ coordinate.setY(2);
/*36*/ coordinate.setOther(other);
Address address = new Address();
/*38*/ address.setAddr("昌北");
/*39*/ address.setCoordinate(coordinate);
School school = new School();
/*41*/ school.setName("华东交大");
/*42*/ school.setAddress(address);
ParamEntiry paramEntiry = new ParamEntiry();
/*44*/ paramEntiry.setName("yc");
/*45*/ paramEntiry.setAge(Integer.valueOf(32));
/*46*/ paramEntiry.setSchool(school);
/*47*/ this.test(paramEntiry);
/*48*/ System.out.println("执行完毕");
}
}
如果不展示行号,加--lineNumber false 参数
[arthas@9388]$ jad com.htf.smm.controller.SmmController --source-only --lineNumber false
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.htf.smm.controller.Address
* com.htf.smm.controller.Coordinate
* com.htf.smm.controller.Other
* com.htf.smm.controller.ParamEntiry
* com.htf.smm.controller.ReturnEntity
* com.htf.smm.controller.School
* com.htf.smm.service.impl.TestServiceOne
*/
package com.htf.smm.controller;
import com.htf.smm.controller.Address;
import com.htf.smm.controller.Coordinate;
import com.htf.smm.controller.Other;
import com.htf.smm.controller.ParamEntiry;
import com.htf.smm.controller.ReturnEntity;
import com.htf.smm.controller.School;
import com.htf.smm.service.impl.TestServiceOne;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping(value={"/smm"})
public class SmmController {
@Autowired
private TestServiceOne testServiceOne;
public ReturnEntity test(ParamEntiry paramEntiry) {
ReturnEntity returnEntity = new ReturnEntity();
Other other = new Other();
other.setInfo("其他");
Coordinate coordinate = new Coordinate();
coordinate.setX(1);
coordinate.setY(2);
coordinate.setOther(other);
Address address = new Address();
address.setAddr("昌北");
address.setCoordinate(coordinate);
School school = new School();
school.setName("华东交大");
school.setAddress(address);
returnEntity.setSchool(school);
return returnEntity;
}
@RequestMapping(value={"/ycTest"})
public void ycTest(Long time) throws InterruptedException {
System.out.println("执行开始," + time);
Other other = new Other();
other.setInfo("其他");
Coordinate coordinate = new Coordinate();
coordinate.setX(1);
coordinate.setY(2);
coordinate.setOther(other);
Address address = new Address();
address.setAddr("昌北");
address.setCoordinate(coordinate);
School school = new School();
school.setName("华东交大");
school.setAddress(address);
ParamEntiry paramEntiry = new ParamEntiry();
paramEntiry.setName("yc");
paramEntiry.setAge(Integer.valueOf(32));
paramEntiry.setSchool(school);
this.test(paramEntiry);
System.out.println("执行完毕");
}
}
反编译类中的方法,如下:
[arthas@9388]$ jad com.htf.smm.controller.SmmController test --source-only --lineNumber false
public ReturnEntity test(ParamEntiry paramEntiry) {
ReturnEntity returnEntity = new ReturnEntity();
Other other = new Other();
other.setInfo("其他");
Coordinate coordinate = new Coordinate();
coordinate.setX(1);
coordinate.setY(2);
coordinate.setOther(other);
Address address = new Address();
address.setAddr("昌北");
address.setCoordinate(coordinate);
School school = new School();
school.setName("华东交大");
school.setAddress(address);
returnEntity.setSchool(school);
return returnEntity;
}
retransform命令,结合 jad/mc 命令使用
1、jad 命令反编译,然后可以用其它编译器
[arthas@9388]$ jad com.htf.smm.controller.SmmController --source-only --lineNumber false > D:\\\tmp\\\SmmController.java
2、修改源码 ,修改了日志输出
3、mc 命令来内存编译修改过的代码
[arthas@9388]$ mc D:\\\tmp\\\SmmController.java -d D:\\\tmp
Memory compiler output:
D:\tmp\com\htf\smm\controller\SmmController.class
Affect(row-cnt:1) cost in 1792 ms.
4、用 retransform 命令加载新的字节码
[arthas@9388]$ retransform D:\\\tmp\\\com\\\htf\\\smm\\\controller\\\SmmController.class
retransform success, size: 1, classes:
com.htf.smm.controller.SmmController
之后调用的时候,日志输出是修改了执行完毕,之前是执行完毕
thread命令
参数名称 | 参数说明 |
---|---|
id | 线程 id |
[n:] | 指定最忙的前 N 个线程并打印堆栈 |
[b] | 找出当前阻塞其他线程的线程 |
[i <value> ] | 指定 cpu 使用率统计的采样间隔,单位为毫秒,默认值为 200 |
[--all] | 显示所有匹配的线程 |
我们用它来排查cpu占比很高的问题
得知占比cpu最高的线程的id是81,执行命令thread 81,如下:
[arthas@16256]$ thread 81
"http-nio-8080-exec-1" Id=81 RUNNABLE
at java.io.FileOutputStream.writeBytes(Native Method)
at java.io.FileOutputStream.write(FileOutputStream.java:307)
at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
at java.io.PrintStream.write(PrintStream.java:482)
at sun.nio.cs.StreamEncoder.writeBytes(StreamEncoder.java:221)
at sun.nio.cs.StreamEncoder.implFlushBuffer(StreamEncoder.java:291)
at sun.nio.cs.StreamEncoder.flushBuffer(StreamEncoder.java:104)
at java.io.OutputStreamWriter.flushBuffer(OutputStreamWriter.java:185)
at java.io.PrintStream.newLine(PrintStream.java:546)
at java.io.PrintStream.println(PrintStream.java:807)
at com.htf.smm.controller.SmmController.test(SmmController.java:66)
at com.htf.smm.controller.SmmController.ycTest(SmmController.java:46)
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:483)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:878)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:792)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1589)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:744)
得知在业务代码
at com.htf.smm.controller.SmmController.test(SmmController.java:66)
at com.htf.smm.controller.SmmController.ycTest(SmmController.java:46)中有问题
参考:
-
monitor——方法执行监控
-
watch——方法执行数据观测,查看方法的入参,出参,和当前对象的属性
-
trace——方法内部调用路径,并输出方法路径上的每个节点上耗时
-
stack——输出当前方法之前到当前方法被调用的调用路径
-
tt——方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测
-
jad反编译
-
redefine /xx/xx.class 更新class文件 服务重启就是失效了
-
dashboard看板,thread命令可以排查cpu和内存飙高问题