arthas使用
用
arthas排查java服务内存占用过高arthas堆外内存分析https://blog.51cto.com/u_16099193/9207218
测试下面的arthas相关命令需要辅助示例https://gitee.com/dexterleslie/demonstration/tree/master/demo-java/demo-java-assistant协助。
编译辅助示例
mvn package运行辅助示例
java -jar target/demo.jararthas安装和运行
参考链接
https://arthas.aliyun.com/doc/quick-start.html注意:如果
java应用使用systemctl运行,请不要把xxx.service配置文件中的PrivateTmp设置为true,否则arthas会报告Unable to open socket file错误。
启动 math-game
bashcurl -O https://arthas.aliyun.com/math-game.jar java -jar math-game.jarmath-game是一个简单的程序,每隔一秒生成一个随机数,再执行质因数分解,并打印出分解结果。math-game源代码https://github.com/alibaba/arthas/blob/master/math-game/src/main/java/demo/MathGame.java启动 arthas
在命令行下面执行(使用和目标进程一致的用户启动,否则可能 attach 失败):
bashcurl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar- 执行该程序的用户需要和目标进程具有相同的权限。比如以
admin用户来执行:sudo su admin && java -jar arthas-boot.jar或sudo -u admin -EH java -jar arthas-boot.jar。 - 如果 attach 不上目标进程,可以查看
~/logs/arthas/目录下的日志。 - 如果下载速度比较慢,可以使用
aliyun的镜像:java -jar arthas-boot.jar --repo-mirror aliyun --use-http - ``java -jar arthas-boot.jar -h` 打印更多参数信息。
选择应用 java 进程:
bash$ $ java -jar arthas-boot.jar * [1]: 35542 [2]: 71560 math-game.jarmath-game进程是第 2 个,则输入 2,再输入回车/enter。Arthas 会 attach 到目标进程上,并输出日志:bash[INFO] Try to attach process 71560 [INFO] Attach process 71560 success. [INFO] arthas-client connect 127.0.0.1 3658 ,---. ,------. ,--------.,--. ,--. ,---. ,---. / O \ | .--. ''--. .--'| '--' | / O \ ' .-' | .-. || '--'.' | | | .--. || .-. |`. `-. | | | || |\ \ | | | | | || | | |.-' | `--' `--'`--' '--' `--' `--' `--'`--' `--'`-----' wiki: https://arthas.aliyun.com/doc version: 3.0.5.20181127201536 pid: 71560 time: 2018-11-28 19:16:24 $- 执行该程序的用户需要和目标进程具有相同的权限。比如以
监控docker容器中的java应用
监控docker容器中的java应用,需要在docker中运行arthas并进行监控即可。
dashboard使用
查看
jvm线程、内存、GC情况参考链接
https://arthas.aliyun.com/doc/dashboard.html
指定每1秒刷新一次,单位毫秒
dashboard -i 1000指定总共刷新5次后退出
dashboard -n 5thread使用
默认按照 CPU 增量时间降序排列,只显示第一页数据。
thread显示所有匹配线程信息,有时需要获取全部 JVM 的线程数据进行分析
thread -all查看指定状态的线程
thread --state RUNNABLE列出5000ms内最忙的6个线程栈
thread -n 6 -i 5000
[arthas@12006]$ thread -n 6 -i 5000
"cpu负载-0" Id=171 cpuUsage=98.69% deltaTime=4936ms time=50311ms RUNNABLE
at app//org.springframework.security.crypto.bcrypt.BCrypt.encipher(BCrypt.java:505)
at app//org.springframework.security.crypto.bcrypt.BCrypt.key(BCrypt.java:595)
at app//org.springframework.security.crypto.bcrypt.BCrypt.crypt_raw(BCrypt.java:707)
at app//org.springframework.security.crypto.bcrypt.BCrypt.hashpw(BCrypt.java:793)
at app//org.springframework.security.crypto.bcrypt.BCrypt.hashpw(BCrypt.java:737)
at app//org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(BCryptPasswordEncoder.java:108)
at com.future.demo.performance.CpuService.consume(CpuService.java:64)
at com.future.demo.performance.CpuService$1.run(CpuService.java:39)
at [email protected]/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at [email protected]/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at [email protected]/java.lang.Thread.run(Thread.java:834)
"cpu负载-1" Id=172 cpuUsage=98.04% deltaTime=4903ms time=49181ms RUNNABLE
at app//org.springframework.security.crypto.bcrypt.BCrypt.encipher(BCrypt.java:505)
at app//org.springframework.security.crypto.bcrypt.BCrypt.key(BCrypt.java:589)
at app//org.springframework.security.crypto.bcrypt.BCrypt.crypt_raw(BCrypt.java:707)
at app//org.springframework.security.crypto.bcrypt.BCrypt.hashpw(BCrypt.java:793)
at app//org.springframework.security.crypto.bcrypt.BCrypt.hashpw(BCrypt.java:737)
at app//org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder.encode(BCryptPasswordEncoder.java:108)
at com.future.demo.performance.CpuService.consume(CpuService.java:64)
at com.future.demo.performance.CpuService$1.run(CpuService.java:39)
at [email protected]/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at [email protected]/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at [email protected]/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at [email protected]/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at [email protected]/java.lang.Thread.run(Thread.java:834)
"File Watcher" Id=145 cpuUsage=0.12% deltaTime=5ms time=2369ms TIMED_WAITING
at [email protected]/java.lang.Thread.sleep(Native Method)
at app//org.springframework.boot.devtools.filewatch.FileSystemWatcher$Watcher.scan(FileSystemWatcher.java:246)
at app//org.springframework.boot.devtools.filewatch.FileSystemWatcher$Watcher.run(FileSystemWatcher.java:236)
at [email protected]/java.lang.Thread.run(Thread.java:834)
"VM Periodic Task Thread" [Internal] cpuUsage=0.09% deltaTime=4ms time=4492ms
"C1 CompilerThread0" [Internal] cpuUsage=0.08% deltaTime=4ms time=8374ms
"GC Thread#2" [Internal] cpuUsage=0.06% deltaTime=2ms time=1026msjvm使用
显示
jvm启动参数、垃圾回收器信息、GC统计信息、内存使用情况、线程信息。
查看当前JVM信息
jvmTHREAD相关
- COUNT:JVM当前活跃的线程数
- DAEMON-COUNT: JVM当前活跃的守护线程数
- PEAK-COUNT:从JVM启动开始曾经活着的最大线程数
- STARTED-COUNT:从JVM启动开始总共启动过的线程次数
- DEADLOCK-COUNT:JVM当前死锁的线程数
memory使用
查看jvm内存使用情况
memorymemory命令输出列对应的意义,参考
- used:目前正在使用的内存大小
- total:之前已经申请使用的内存,
committed内存 - max:可支持最大内存
sysprop使用
查看当前
JVM的系统属性(System Property) 参考链接
查看所有属性
sysprop查看单个属性
sysprop java.version修改单个属性
sysprop user.country CNvmoption使用
查看,修改VM诊断相关的参数 参考链接
TODO logger
查看logger信息,更新logger level 参考链接
heapdump使用
dump java heap, 类似jmap命令的heap dump功能。参考链接
dump到指定文件
heapdump /tmp/dump.hprof
# 在应用运行的当前目录中创建dump.hprof文件
heapdump dump.hprof只dump live对象
heapdump --live /tmp/dump.hprofdump到/tmp/xxx.hprof
heapdumpTODO mbean
TODO ognl
TODO vmtool
monitor命令
对匹配 class-pattern/method-pattern/condition-express的类、方法的调用进行监控。统计每个周期内方法调用次数和平均调用耗时(毫秒数)。参考链接
https://arthas.aliyun.com/doc/monitor.html
对类com.future.demo.performance.ApiArthasController的monitorMethod方法每5秒为一个周期进行监控
monitor -c 5 com.future.demo.ArthasController monitorMethod-c参数表示每5秒为一个周期对方法monitorMethod进行监控,直到ctrl+c终止。
调用接口http://localhost:8080/api/v1/arthas/monitor触发方法被调用。
watch命令
让你能方便的观察到指定函数的调用情况。能观察到的范围为:返回值、抛出异常、入参,通过编写
OGNL表达式进行对应变量的查看。参考链接https://arthas.aliyun.com/doc/watch.html
注意:下面的实验需要通过调用接口http://localhost:8080/api/v1/arthas/watch触发。
观察函数调用返回时的参数、this 对象和返回值
watch com.future.demo.ArthasService watchMethod "{params,target,returnObj}" -x 2"{params,target,returnObj}"指定了你对方法监控时感兴趣的内容,这里表示你想查看方法的参数(params)和返回值(returnObj)。-x 2表示在输出结果时,对于参数和返回值的复杂对象,应该展开两层来显示其内部结构。这意味着如果参数或返回值是一个对象,其直接属性会被显示;如果这些属性本身也是对象,那么这些对象的直接属性也会被显示,但不会再深入展开。
查看指定的方法入参和返回值,输出结果的属性遍历深度为2
watch com.future.demo.ArthasService watchMethod "{params,returnObj}" -x 2在方法调用前后打印成员变量watchCount的值
watch com.future.demo.ArthasService watchMethod "{target.watchCount}" -x 2 -b -s- 在函数调用之前观察。
- 在函数返回之后观察
捕捉4次后自动退出命令
watch com.future.demo.ArthasService watchMethod "{target.watchCount}" -x 2 -b -s -n 4过滤第二个参数等于0才输出ognl表达式
watch com.future.demo.ArthasService watchMethod "{params,target}" "params[1]==0" -x 2方法抛出异常时被捕捉
watch com.future.demo.ArthasService watchMethod "{params,target,returnObj,throwExp}" -e -x 2-e表示抛出异常时才触发express中,表示异常信息的变量是throwExp
按照方法调用耗时过滤
watch com.future.demo.ArthasService watchMethod '{params, returnObj}' '#cost>200' -x 2#cost>200(单位是ms)表示只有当耗时大于200ms时才会输出,过滤掉执行时间小于200ms的调用
返回值第二个参数为0才捕捉
watch com.future.demo.ArthasService watchMethod "{params,target,returnObj,throwExp}" "returnObj[1]==0" -x 2返回值第一个参数为包含aa才捕捉
watch com.future.demo.ArthasService watchMethod "{params,target,returnObj,throwExp}" 'returnObj[0].contains("aa")' -x 2trace命令
trace 命令能主动搜索 class-pattern/method-pattern 对应的方法调用路径,渲染和统计整个调用链路上的所有性能开销和追踪调用链路。参考链接
https://arthas.aliyun.com/doc/trace.html
追踪指定方法
traceMethodLv1调用链路开销bashtrace com.future.demo.performance.ArthasService traceMethodLv1 [arthas@12006]$ trace com.future.demo.performance.ArthasService traceMethodLv1 Press Q or Ctrl+C to abort. Affect(class count: 3 , method count: 3) cost in 156 ms, listenerId: 5 `---ts=2024-07-02 09:00:03;thread_name=http-nio-8080-exec-12;id=158;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@20edb5bc `---[2903.8607ms] com.future.demo.performance.ArthasService:traceMethodLv1() +---[18.10% 525.461178ms ] com.future.demo.performance.ArthasService:sleepRandomly() #31 `---[81.88% 2377.696287ms ] com.future.demo.performance.ArthasService:traceMethodLv2() #32 `---ts=2024-07-02 09:00:07;thread_name=http-nio-8080-exec-13;id=159;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@20edb5bc `---[3543.337142ms] com.future.demo.performance.ArthasService:traceMethodLv1() +---[30.99% 1097.937776ms ] com.future.demo.performance.ArthasService:sleepRandomly() #31 `---[69.00% 2444.977755ms ] com.future.demo.performance.ArthasService:traceMethodLv2() #32 `---ts=2024-07-02 09:00:15;thread_name=http-nio-8080-exec-14;id=160;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@20edb5bc `---[3264.46721ms] com.future.demo.performance.ArthasService:traceMethodLv1() +---[27.60% 900.833107ms ] com.future.demo.performance.ArthasService:sleepRandomly() #31 `---[72.40% 2363.455824ms ] com.future.demo.performance.ArthasService:traceMethodLv2() #32统计指定包下执行时间大于
1秒的函数根据调用耗时过滤
https://arthas.aliyun.com/doc/trace.html#%E6%A0%B9%E6%8D%AE%E8%B0%83%E7%94%A8%E8%80%97%E6%97%B6%E8%BF%87%E6%BB%A4运行辅助示例
https://gitee.com/dexterleslie/demonstration/tree/master/demo-java/demo-java-assistant访问
http://localhost:8080/api/v1/arthas/trace触发调用trace统计命令
bashtrace com.future.demo.* * '#cost > 1000'
stack命令
stack命令能主动搜索 class-pattern/method-pattern 对应的方法完整的上游调用链路。参考链接https://arthas.aliyun.com/doc/trace.html
追踪指定方法traceMethodLv1上游调用链路
stack com.future.demo.performance.ArthasService traceMethodLv1
[arthas@12006]$ stack com.future.demo.performance.ArthasService traceMethodLv1
Press Q or Ctrl+C to abort.
Affect(class count: 3 , method count: 3) cost in 186 ms, listenerId: 6
ts=2024-07-02 09:03:33;thread_name=http-nio-8080-exec-17;id=163;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@20edb5bc
@com.future.demo.performance.ArthasService.traceMethodLv1()
at com.future.demo.performance.ApiArthasController.trace(ApiArthasController.java:71)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:566)
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:879)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
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:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
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.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
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.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
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.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
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.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.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:1594)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:834)sm命令
Arthas中的sm命令是“Search-Method”的简写,该命令用于搜索并展示所有已经加载到JVM中的类的方法信息。以下是关于sm命令的详细解释:
功能
sm命令可以列出指定类(或符合特定模式的类)的所有方法信息,包括方法的名称、参数类型、返回类型等。这对于了解类的功能、接口以及进行代码调试非常有帮助。
使用方法
基本语法:
sm [class-pattern] [method-pattern]class-pattern:类名表达式匹配,支持通配符(如*)和正则表达式(需开启-E选项)。method-pattern:方法名表达式匹配,同样支持通配符和正则表达式。
常用选项:
-d:展示每个方法的详细信息,包括方法的签名、参数类型、返回类型等。-E:开启正则表达式匹配,默认为通配符匹配。
示例:
展示
java.lang.String类加载的所有方法:sm java.lang.String展示
java.lang.String类中名为toString的方法的详细信息:sm -d java.lang.String toString使用正则表达式匹配类名(如匹配所有以
Controller结尾的类),并展示其方法信息:sm -E .*Controller$使用正则表达式匹配类名(如匹配所有在包
com.future内以Controller结尾的类),并展示其方法信息:sm -E com.future.*Controller$查看是否存在
com.future.demo.ArthasController#monitorMethod方法bashsm -d com.future.demo.ArthasController monitorMethod
注意事项
sm命令只能看到由当前类所声明的方法,无法看到父类或接口的方法。- 在使用通配符进行匹配时,需要注意匹配的范围和精度,以避免匹配到过多的类导致信息混乱。
- 当类名或方法名包含特殊字符或空格时,需要使用引号将其括起来。
应用场景
- 代码调试:在调试过程中,可以通过
sm命令查看某个类的方法信息,以了解该类的功能和接口。 - 性能分析:在性能分析过程中,可以通过
sm命令查看某个类的方法调用情况,以找出性能瓶颈或优化点。 - 代码审查:在代码审查过程中,可以通过
sm命令查看某个类的方法签名和参数类型等信息,以判断代码是否符合规范或存在潜在问题。
总之,sm命令是Arthas中非常实用的一个命令,它可以帮助开发者快速了解类的方法信息,为代码调试、性能分析和代码审查等工作提供有力支持。
sc命令
Arthas中的sc命令是“Search-Class”的简写,主要用于搜索并查看已经加载到JVM中的类信息。以下是关于Arthas sc命令的详细介绍:
基本用法
在Arthas的交互式命令行界面中,输入sc命令后跟上类名或类名的部分匹配模式,即可搜索出符合条件的类信息。例如:
sc java.lang.String:搜索并显示java.lang.String类的信息。sc demo.*:使用通配符搜索demo包下的所有类。
参数说明
sc命令支持多个参数,以提供更详细的类信息或进行更复杂的搜索。以下是一些常用的参数:
-d:显示类的详细信息,包括类名、是否是接口、是否是注解、是否是枚举等,以及类的修饰符、注解、实现的接口、继承的父类等信息。-f:显示类的字段信息。-x:决定静态变量的遍历深度。例如,-x 1会打印出静态属性的第一层属性。-E:支持正则表达式搜索,可以搜索符合正则表达式的类名。
示例
搜索并显示类的详细信息:
shellsc -d demo.MathGame这条命令将搜索
demo.MathGame类,并显示其详细信息,包括类名、修饰符、注解、实现的接口、继承的父类等。搜索并显示类的字段信息:
shellsc -d -f demo.MathGame除了显示类的详细信息外,这条命令还将显示
demo.MathGame类的字段信息。使用正则表达式搜索类:
shellsc -E ".*Test$"这条命令将搜索所有以
Test结尾的类名。
注意事项
- 在使用sc命令时,需要确保所搜索的类已经加载到JVM中。如果类尚未加载,sc命令将无法搜索到该类。
- sc命令的结果可能受到JVM的类加载器机制的影响。在某些情况下,可能需要指定特定的类加载器来搜索类。
总的来说,Arthas的sc命令是一个强大的工具,可以帮助Java开发者快速搜索并查看已经加载到JVM中的类信息。通过合理使用sc命令及其参数,开发者可以更有效地进行Java应用的在线诊断和调试。
jad命令
Arthas中的jad命令是一个强大的工具,它允许开发者反编译已经加载到JVM中的Java类,并查看其源代码。这对于理解第三方库或框架的内部实现,以及调试和诊断Java应用中的问题时非常有用。
基本用法
在Arthas的交互式命令行界面中,使用jad命令后跟上要反编译的类的全限定名(包括包名和类名),即可查看该类的源代码。例如:
jad com.example.MyClass这将反编译com.example.MyClass类,并在控制台上显示其源代码。
参数和选项
jad命令支持一些参数和选项,以提供更灵活的反编译功能:
- 类名模式:
_class-pattern_是必填参数,用于指定要反编译的类名。支持通配符匹配,例如com.example.*可以匹配com.example包下的所有类。 - 类加载器:可以通过
-c选项指定类加载器的哈希码,以选择特定的类加载器。当存在多个类加载器加载了相同名称的类时,这个选项非常有用。 - 正则表达式:使用
-E选项可以启用正则表达式匹配类名,而不是默认的通配符匹配。 - 源代码格式:
--source-only选项可以让jad命令仅输出反编译得到的源代码,而不包含类加载器信息等额外元数据。 - 行号:
--lineNumber [true|false]选项可以控制是否在输出的源代码中包含行号。默认为true,如果设置为false,则不显示行号。 - 输出目录:使用
-d或--directory选项可以指定一个目录,将反编译得到的源代码保存到该目录中,而不是显示在控制台上。
示例
- 反编译单个类:
jad com.example.MyClass- 使用正则表达式匹配类名:
jad -E "com\.example\..*Service$"这将匹配所有以Service结尾的,位于com.example包及其子包下的类。
- 指定类加载器:
jad -c <classloader-hash> com.example.MyClass你需要先使用Arthas的sc -d命令或其他方法来获取类加载器的哈希码。
- 反编译并保存到文件:
jad --source-only com.future.demo.ArthasService > /home/dexterleslie/1.java注意事项
- 反编译得到的源代码可能与原始源代码不完全一致,因为反编译过程可能无法完全恢复原始代码的某些部分(如注释、泛型类型参数的具体化等)。
- 在使用
jad命令时,需要确保所反编译的类已经加载到JVM中。如果类尚未加载,jad命令将无法找到该类。 - 由于反编译涉及到对字节码的分析和转换,因此可能会对性能产生一定影响。在生产环境中使用时,请谨慎操作。
mc命令
Arthas(Alibaba Java Diagnostic Tool)是一款面向Java应用的开源诊断工具,它提供了丰富的功能来帮助开发者定位和解决Java应用中的问题。mc(Memory Compiler)命令是Arthas中的一个重要功能,它允许开发者在运行时动态编译和执行Java代码。
以下是mc命令的一些关键用法和示例:
基本用法
mc -c <className> <source>-c:指定要编译的类名。<source>:Java源代码,可以是直接写在命令行中的代码片段,也可以是一个文件路径。
示例
- 直接编写代码片段
mc -c HelloWorld 'public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } }' -e这个命令会在内存中编译一个名为HelloWorld的类,并立即执行它的main方法。-e选项表示执行编译后的类。
- 从文件中读取源代码
假设你有一个名为HelloWorld.java的文件,内容如下:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}你可以使用以下命令来编译并执行它:
mc -c HelloWorld /path/to/HelloWorld.java -e同样,-e选项表示执行编译后的类。
注意事项
- 依赖管理:
mc命令只能编译简单的Java类,如果类依赖于其他库或包,你可能需要手动将这些依赖添加到类路径中。 - 安全性:动态编译和执行代码可能会带来安全风险,特别是在生产环境中。确保你信任并理解正在执行的代码。
- 性能:虽然
mc命令在开发和调试阶段非常有用,但在生产环境中频繁使用可能会影响性能。
高级用法
- 指定输出目录:你可以使用
-d选项来指定编译后的类文件的输出目录。 - 指定类加载器:使用
-l选项可以指定用于加载编译后的类的类加载器。
mc -c ArthasService /home/dexterleslie/1.java -d /home/dexterleslie -l <classLoaderHash><classLoaderHash>是目标类加载器的哈希值,你可以使用Arthas的sc(Search Class)命令来查找类加载器的哈希值。
总结
mc命令是Arthas中非常强大的一个功能,它允许开发者在运行时动态编译和执行Java代码,这对于快速调试和验证代码非常有帮助。然而,在使用时需要注意安全性和性能问题,特别是在生产环境中。
在线热更新class
注意:不知道什么原因没有成功加载新的class到jvm中。
获取classloader hash值
sc -d com.future.demo.ArthasService反编译输出源码到ArthasService.java文件
jad --source-only com.future.demo.ArthasService > /home/dexterleslie/ArthasService.java手动修改ArthasService.java源码
通过ArthasService.java源码编译ArthasService.class
mc -c 31cefde0 /home/dexterleslie/ArthasService.java -d /home/dexterleslie-c 31cefde0是命令sc -d com.future.demo.ArthasService获取的classloader hash值
重新加载ArthasService.class字节码到jvm
redefine -c 31cefde0 /home/dexterleslie/com/future/demo/ArthasService.class查看方法逻辑是否被修改
watch com.future.demo.ArthasService watchMethod '{params,target,returnObj}' -x 2 -b -sprofiler使用
什么是profiler?
Arthas的profiler命令是一个强大的工具,它在Java应用程序的性能分析和调优中扮演着关键角色。这个命令通过利用async-profiler库(或其他类似的性能分析工具,具体取决于Arthas的版本和配置)来收集应用程序运行时的各种性能数据。以下是arthas profiler命令的主要作用:
- 热点分析:
profiler可以帮助开发者识别应用程序中的热点代码区域,即执行频率高、消耗资源多的代码段。这有助于开发者优先关注那些对性能影响最大的部分,从而进行针对性的优化。 - 内存分配分析:当使用
profiler alloc等子命令时,profiler可以跟踪Java堆中的内存分配情况。这有助于识别内存泄漏、不必要的内存分配和内存使用效率低下的问题。通过分析内存分配热点,开发者可以优化数据结构、减少内存占用和提高内存使用效率。 - 锁竞争分析:某些
profiler子命令(如profiler lock)可以跟踪Java中的锁竞争情况。这有助于识别死锁、锁争用和锁饥饿等问题,这些问题可能会导致应用程序的性能下降甚至崩溃。通过分析锁竞争热点,开发者可以优化同步机制、减少锁的使用或改进锁的策略。 - CPU性能分析:使用
profiler cpu等子命令时,profiler可以收集CPU使用情况的数据。这有助于识别哪些代码段占用了最多的CPU时间,从而找到性能瓶颈。通过分析CPU使用热点,开发者可以优化算法、减少不必要的计算或并行化代码以提高性能。 - 火焰图生成:
profiler收集的数据通常以火焰图的形式展示。火焰图是一种性能分析的可视化工具,它通过堆叠的条形图来表示方法的调用关系和调用时间。这种图形化的表示方式使得性能分析更加直观和易于理解。 - 非侵入式分析:与传统的性能分析工具相比,
arthas profiler通常不需要修改应用程序的代码或重新编译。这使得它成为一种非侵入式的性能分析方法,可以在不中断应用程序正常运行的情况下进行性能分析。 - 动态分析:
arthas profiler支持在应用程序运行时动态地启动和停止性能分析。这使得开发者可以在需要时快速地进行性能分析,而无需事先进行复杂的设置或配置。
总之,arthas profiler是一个功能强大的性能分析工具,它可以帮助开发者识别和解决Java应用程序中的性能问题。通过热点分析、内存分配分析、锁竞争分析、CPU性能分析以及火焰图的生成等功能,arthas profiler为Java应用的性能调优提供了有力的支持。
CPU火焰图
编译并运行demo-springboot-performance演示项目,注意:需要使用
java -jar demo-springboot-performance.jar -Xmx4g -Xms4g命令运行使用
jmeter打开cpu负载.jmx用于给应用加cpu负载运行
arthas并选择demo-springboot-performance进程生成
cpu火焰图bash# 默认是--event cpu,对cpu生成火焰图 profiler start # 查看profiler状态 profiler status # 查看已经采样的个数 profiler getSamples # 停止采样并输出html格式的火焰图 profiler stop使用浏览器打开火焰图对应的
html,html在目录arthas-output中在火焰图中能够直观地看到
com/future/demo/performance/CpuService.consume最宽表示占用cpu时间最多
内存分配火焰图
编译并运行demo-springboot-performance演示项目,注意:需要使用
java -jar demo-springboot-performance.jar -Xmx4g -Xms4g命令运行使用
jmeter打开memory负载.jmx用于给应用加内存分配负载运行
arthas并选择demo-springboot-performance进程生成
cpu火焰图bash# 对内存分配生成火焰图 profiler start --event alloc # 查看profiler状态 profiler status # 查看已经采样的个数 profiler getSamples # 停止采样并输出html格式的火焰图 profiler stop使用浏览器打开火焰图对应的
html,html在目录arthas-output中在火焰图中能够直观地看到
com/future/demo/performance/ApiMemoryController.alloc比较宽表示内存分配比较多