arthas 基本使用
https://arthas.aliyun.com/doc/
查看java内存中对象
vmtool --action getInstances --className com.zaxxer.hikari.pool.HikariPool -x 3
用来查看连接池信息,可以在没有工具类的情况下,查看spring容器中的信息
arthas之火焰图
查询mybatis的sql执行语句
查询Mybatis执行的sql:
经常不知道mysql执行的什么语句,可以用如下语句去监控mysql的执行语句。
注意UPDATE 即代表 更新。 SELECT 同理。
watch org.apache.ibatis.mapping.BoundSql getSql -n 5 'returnObj' 'returnObj.indexOf("UPDATE")!=-1'
1
这里returnObj是观察了返回值
动态jvm参数
使用dashboard命令查看GC信息
在dashboard命令里可以直接看到GC的数据,次数和时间:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wbegTK2A-1658635420146)(https://www.wangdaye.net/upload/2021/11/image-e2b1a567ab33471c89affaa5cf89f2d4.png)]
使用vmoption命令动态打开GC日志
$ vmoption PrintGC true
Successfully updated the vm option.
NAME BEFORE-VALUE AFTER-VALUE
------------------------------------
PrintGC false true
$ vmoption PrintGCDetails true
Successfully updated the vm option.
NAME BEFORE-VALUE AFTER-VALUE
-------------------------------------------
PrintGCDetails false true
打开上面两个选项之后,当应用发生GC时,就会在标准输出里打印GC日志。
使用vmtool强制GC
$ vmtool --action forceGc
[GC (JvmtiEnv ForceGarbageCollection) [PSYoungGen: 2184K->352K(76288K)] 19298K->17474K(166912K), 0.0011562 secs] [Times: user=0.01 sys=0.00, real=0.00 secs]
[Full GC (JvmtiEnv ForceGarbageCollection) [PSYoungGen: 352K->0K(76288K)] [ParOldGen: 17122K->16100K(90112K)] 17474K->16100K(166400K), [Metaspace: 20688K->20688K(1069056K)], 0.0232947 secs] [Times: user=0.14 sys=0.01, real=0.03 secs]
在GC前后,执行heapdump
在排查GC问题时,我们有时需要对比GC前后,生成heapdump文件,然后再做对比。
-
打开HeapDumpBeforeFullGC开关,可以在GC前生成heapdump文件 -
打开HeapDumpAfterFullGC开关,可以在GC结束后生成heapdump文件
$ vmoption HeapDumpBeforeFullGC true
Successfully updated the vm option.
NAME BEFORE-VALUE AFTER-VALUE
-------------------------------------------------
HeapDumpBeforeFullGC false true
$ vmtool --action forceGc
再使用vmtool --action forceGc强制GC,则可以在GC日志中发现heapdump信息,并且在应用目录下会生成heapdump hprof文件:
#9: [Heap Dump (before full gc): Dumping heap to java_pid69445.hprof ...
Heap dump file created [23915304 bytes in 0.107 secs]
再使用其它堆分析软件,对比两个heapdump文件,就可以知道GC到底回收了哪些对象。
在GC前后,打印类直方图
排查GC问题时,我们有时需要统计每个类加载的数量和占用内存大小。
-
打开`PrintClassHistogramBeforeFullGC`开关,可以在GC前打印类直方图 -
打开`PrintClassHistogramAfterFullGC`开关,可以在GC结束后打印类直方图
$ vmoption PrintClassHistogramBeforeFullGC true
Successfully updated the vm option.
NAME BEFORE-VALUE AFTER-VALUE
------------------------------------------------------------
PrintClassHistogramBeforeFullGC false true
$ vmtool --action forceGc
再使用vmtool --action forceGc强制GC,在GC日志中会打印类直方图,可以直观知道每个类的instances数量,占用内存大小:
#13: [Class Histogram (before full gc):
num #instances #bytes class name
----------------------------------------------
1: 24519 5783400 [C
2: 5648 5102712 [B
3: 3685 888128 [Ljava.lang.Object;
4: 3255 619560 [I
5: 24263 582312 java.lang.String
6: 4227 475320 java.lang.Class
7: 1288 402112 [Ljava.util.HashMap$Node;
8: 75 296160 [Ljava.nio.channels.SelectionKey;
9: 6759 216288 java.util.HashMap$Node
10: 2069 182072 java.lang.reflect.Method
11: 3326 133040 java.util.LinkedHashMap$Entry
Thread
介绍
jstack
很相似,但是功能更加强大,主要是查看当前
JVM
的线程堆栈信息
同时可以结合使用
thread –b
来进行死锁的排查死锁。
参数解释:
-n
指定最忙的前
n
个线程并打印堆栈
-b
找出阻塞当前线程的线程
-i
指定
cpu
占比统计的采样间隔,单位为毫秒
实战演示
thread 显示线程信息
thread –h
显示帮助
thread –b 找出阻塞当前线程的线程
如图:
如果有死锁,会有红色的字提醒着,这个阻塞的线程已经被另外一个线程阻塞。
采样
thread -i 1000 -n 3
每过
1000
毫秒进行采样,显示最占
CPU
时间的前
3
个线程
thread --state WAITING
查看处于等待状态的线程
3、JVM
其他小技巧
查看第一个参数:
$ watch com.taobao.container.Test test "params[0]"
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 34 ms.
@ArrayList[
@Pojo[com.taobao.container.Test$Pojo@75a1cd57],
@Pojo[com.taobao.container.Test$Pojo@3d012ddd],
@Pojo[com.taobao.container.Test$Pojo@6f2b958e],
@Pojo[com.taobao.container.Test$Pojo@1eb44e46],
@Pojo[com.taobao.container.Test$Pojo@6504e3b2],
查看第一个参数的size:
$ watch com.taobao.container.Test test "params[0].size()"
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 22 ms.
@Integer[40]
将结果按name属性投影:
$ watch com.taobao.container.Test test "params[0].{ #this.name }"
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 25 ms.
@ArrayList[
@String[name 0],
@String[name 1],
按条件过滤:
$ watch com.taobao.container.Test test "params[0].{? #this.name == null }" -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 27 ms.
@ArrayList[
@Pojo[
name=null,
age=@Integer[32],
hobby=null,
],
]
@ArrayList[
@Pojo[
name=null,
age=@Integer[31],
hobby=null,
],
]
$ watch com.taobao.container.Test test "params[0].{? #this.name != null }" -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 24 ms.
@ArrayList[
@Pojo[
name=@String[name 1],
age=@Integer[3],
hobby=null,
],
过滤后统计:
$ watch com.taobao.container.Test test "params[0].{? #this.age > 10 }.size()" -x 2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 29 ms.
@Integer[31]
@Integer[31]
访问静态变量
- 在watch命令中访问如下,但是会受到classloader的限制,不推荐使用
$ watch com.taobao.container.Test test "@com.taobao.container.Test@m"
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 36 ms.
@HashMap[
@String[a]:@String[aaa],
@String[b]:@String[bbb],
]
- 使用新版本中的getstatic命令,通过-c指定classloader,可以查看任意static变量,同时支持ognl表达式处理
$ getstatic com.alibaba.arthas.Test n 'entrySet().iterator.{? #this.key.name()=="STOP"}'
field: n
@ArrayList[
@Node[STOP=bbb],
]
Affect(row-cnt:1) cost in 68 ms.
$ getstatic com.alibaba.arthas.Test m 'entrySet().iterator.{? #this.key=="a"}'
field: m
@ArrayList[
@Node[a=aaa],
]
调用静态方法(需手动触发test方法以触发执行ognl表达式)
方法一
$ watch com.taobao.container.Test test "@java.lang.Thread@currentThread()"
方法二
ognl '@java.lang.System@out.println("hello ognl")'
调用静态方法再调用非静态方法(同上)
$ watch com.taobao.container.Test test "@java.lang.Thread@currentThread().getContextClassLoader()"
watch/monitor/trace 等判断重载函数/同名函数
第一种方式,判断params的length:
$ watch Test hello params params.length==2
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:2) cost in 21 ms.
ts=2019-01-07 19:50:17; [cost=0.103617ms] result=@Object[][
@Integer[109],
@String[world],
]
ts=2019-01-07 19:50:18; [cost=0.185045ms] result=@Object[][
@Integer[110],
@String[world],
]
第二种方式,判断params的类型(注意,这里因为int会被包装为Object,所以params[0]
的类型是java.lang.Integer
):
$ watch Test hello params 'params[0].class.name=="java.lang.Integer"'
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:2) cost in 25 ms.
ts=2019-01-07 19:54:59; [cost=0.358485ms] result=@Object[][
@Integer[390],
@String[world],
]
ts=2019-01-07 19:55:00; [cost=0.211562ms] result=@Object[][
@Integer[391],
@String[world],
]
获取spring之context
Arthas之调用SpringBoot获取Bean · wangdaye’s blog
自定义static获取Bean之工具类
arthas之热更新操作
Arthas之热更新骚操作 · wangdaye’s blog
定位到内部类
sc com.ydl.message.service.facade.JPushFacadeImpl$AspectCall
如何trace到更深层之trace/watch之连续自动增强
以前在trace或者watch多个类和函数时,需要写正则表达式匹配多个对象。使用非常不方便。
尝试一个新特性,给已运行的 trace/watch 命令增加新的匹配类和函数。
原理是,每个command都和一个 listener 关联;新执行一个command,传入 listener id,然后查找到已有的 listener,然后增强。
测试版本可以在这里下载: #1184
在窗口1里对 arthas-demo 进行trace trace demo.MathGame run
:
[arthas@71839]$ trace demo.MathGame run
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 87 ms, listenerId: 1
`---ts=2020-05-25 01:52:27;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.849849ms] demo.MathGame:run()
+---[0.142048ms] demo.MathGame:primeFactors() #24
`---[0.177514ms] demo.MathGame:print() #25
可以看到 listenerId是1 。
然后打开一个新的窗口, telnet localhost 3658 ,执行 trace demo.MathGame primeFactors --listenerId 1
:
[arthas@71839]$ trace demo.MathGame primeFactors --listenerId 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 37 ms, listenerId: 1
可以看到窗口1里增加了trace深度:
`---ts=2020-05-25 01:54:01;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.254854ms] demo.MathGame:run()
`---[0.125945ms] demo.MathGame:primeFactors() #24 [throws Exception]
`---[0.07948ms] demo.MathGame:primeFactors()
`---[0.024928ms] throw:java.lang.IllegalArgumentException() #46
`---ts=2020-05-25 01:54:02;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@3d4eac69
`---[0.287046ms] demo.MathGame:run()
+---[0.108534ms] demo.MathGame:primeFactors() #24
| `---[0.066629ms] demo.MathGame:primeFactors()
`---[0.072959ms] demo.MathGame:print() #25
Arthas之使用火焰图
- arthas是什么
- 教程2
- 官方文档
- 热加载
- arthas远程调试
- 如何后台运行搜集日志
- [写的不错的博客](