-
Notifications
You must be signed in to change notification settings - Fork 7.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Arthas里 Trace 命令怎样工作的/ Trace命令的实现原理 #597
Comments
为什么trace结果有时会有多层?在下面的
import java.util.concurrent.TimeUnit;
public class Demo {
public static void main(String[] args) throws InterruptedException {
ClassD d = new ClassD();
while (true) {
TimeUnit.SECONDS.sleep(1);
d.hello();
}
}
interface Hello {
public void hello();
}
static class ClassA implements Hello {
@Override
public void hello() {
System.out.println(this.getClass().getName() + "hello");
}
}
static class ClassB {
public void test() {
System.out.println(this.getClass().getName() + "hello");
new ClassA().hello();
}
}
static class ClassC {
public void test() {
System.out.println(this.getClass().getName() + "hello");
new ClassB().test();
}
}
static class ClassD implements Hello {
public void hello() {
System.out.println(this.getClass().getName() + "hello");
new ClassC().test();
}
}
} 下面用arthas执行 $ trace Demo$ClassD hello
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 96 ms.
`---ts=2019-03-22 19:04:19;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@4e25154f
`---[3.911624ms] Demo$ClassD:hello()
+---[0.032104ms] java.lang.Object:getClass()
+---[0.016964ms] java.lang.Class:getName()
+---[0.016445ms] java.lang.String:valueOf()
+---[0.015006ms] java.lang.StringBuilder:<init>()
+---[0.01918ms] java.lang.StringBuilder:append()
+---[0.01548ms] java.lang.StringBuilder:toString()
+---[1.409546ms] java.io.PrintStream:println()
+---[0.01654ms] Demo$ClassC:<init>()
`---[0.688504ms] Demo$ClassC:test() 下面再用arthas来trace $ trace Demo$Hello hello
Press Q or Ctrl+C to abort.
Affect(class-cnt:2 , method-cnt:2) cost in 29 ms.
`---ts=2019-03-22 19:04:40;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@4e25154f
`---[1.019782ms] Demo$ClassD:hello()
+---[0.008038ms] java.lang.Object:getClass()
+---[0.008512ms] java.lang.Class:getName()
+---[0.00866ms] java.lang.String:valueOf()
+---[0.02074ms] java.lang.StringBuilder:<init>()
+---[0.01381ms] java.lang.StringBuilder:append()
+---[0.006114ms] java.lang.StringBuilder:toString()
+---[0.110468ms] java.io.PrintStream:println()
+---[0.009324ms] Demo$ClassC:<init>()
`---[0.59506ms] Demo$ClassC:test()
`---[0.416302ms] Demo$ClassA:hello()
+---[0.00866ms] java.lang.Object:getClass()
+---[0.01141ms] java.lang.Class:getName()
+---[0.012544ms] java.lang.String:valueOf()
+---[0.013024ms] java.lang.StringBuilder:<init>()
+---[0.065776ms] java.lang.StringBuilder:append()
+---[0.016712ms] java.lang.StringBuilder:toString()
`---[0.060616ms] java.io.PrintStream:println() 可以看到:
为什么 因为trace匹配的是 总结
|
Trace 还有两个常见问题:
以上面的demo为例,如果想把整个4层的调用树列出来,那么可以执行
那么会把完整的调用树打印出来: $ trace -E 'Demo\$Hello|Demo\$ClassB|Demo\$ClassC' 'hello|test'
Press Q or Ctrl+C to abort.
Affect(class-cnt:4 , method-cnt:4) cost in 99 ms.
`---ts=2019-03-22 19:17:53;thread_name=main;id=1;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@4e25154f
`---[3.07526ms] Demo$ClassD:hello()
+---[0.034132ms] java.lang.Object:getClass()
+---[0.015133ms] java.lang.Class:getName()
+---[0.012802ms] java.lang.String:valueOf()
+---[0.010077ms] java.lang.StringBuilder:<init>()
+---[0.010013ms] java.lang.StringBuilder:append()
+---[0.010582ms] java.lang.StringBuilder:toString()
+---[0.17528ms] java.io.PrintStream:println()
+---[0.022878ms] Demo$ClassC:<init>()
`---[2.404445ms] Demo$ClassC:test()
`---[2.158ms] Demo$ClassC:test()
+---[0.01101ms] java.lang.Object:getClass()
+---[0.016783ms] java.lang.Class:getName()
+---[0.016797ms] java.lang.String:valueOf()
+---[0.020633ms] java.lang.StringBuilder:<init>()
+---[0.017495ms] java.lang.StringBuilder:append()
+---[0.010945ms] java.lang.StringBuilder:toString()
+---[0.043742ms] java.io.PrintStream:println()
+---[0.019857ms] Demo$ClassB:<init>()
`---[1.741185ms] Demo$ClassB:test()
`---[1.581065ms] Demo$ClassB:test()
+---[0.173202ms] java.lang.Object:getClass()
+---[0.019643ms] java.lang.Class:getName()
+---[0.019705ms] java.lang.String:valueOf()
+---[0.013422ms] java.lang.StringBuilder:<init>()
+---[0.021875ms] java.lang.StringBuilder:append()
+---[0.096128ms] java.lang.StringBuilder:toString()
+---[0.050018ms] java.io.PrintStream:println()
+---[0.02202ms] Demo$ClassA:<init>()
`---[0.798537ms] Demo$ClassA:hello()
`---[0.641463ms] Demo$ClassA:hello()
+---[0.010265ms] java.lang.Object:getClass()
+---[0.02994ms] java.lang.Class:getName()
+---[0.015822ms] java.lang.String:valueOf()
+---[0.034097ms] java.lang.StringBuilder:<init>()
+---[0.015282ms] java.lang.StringBuilder:append()
+---[0.010235ms] java.lang.StringBuilder:toString()
`---[0.038225ms] java.io.PrintStream:println() |
trace的方法是有入参的,所以trace是如何构造参数的? |
trace不支持获取入参。 |
我trace的方法也是有入参的,不太明白具体入参怎么写? |
min/max/total/count 意义解析public class Test {
public static void main(String[] args) {
for(;;) {
aaa();
}
}
public static void aaa() {
for(int i = 1; i < 10; ++i) {
bbb(i);
System.err.println(i);
}
}
public static void bbb(int i ) {
try {
Thread.sleep(i * 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} 启动上面的demo,然后执行
那么这一行红色的是什么意思呢?
|
请问下,trace命令对性能的压力大不大,目前碰到线程池超时的线上问题,很难复现,想要通过异步任务 + trace指令来排查和记录问题,但是担心这种方式会有大的性能瓶颈/ |
就是说Trace的机制其实不适合看追踪一个函数执行过程,包括所有下级调用。这种场景有其他合适的函数吗 |
3.3.0 版本后,增加动态trace功能,可以动态深入下一层: https://alibaba.github.io/arthas/trace.html
Trace只对匹配到的method内的 子method 做统计
常见的一个疑问是 trace命令为什么有时候输出有时候是只有一级的,有时候是多级的?
首先trace命令的原理是:对匹配到的method内的 子method 做统计。
比如这个简单的
Demo
类:使用arthas执行
trace Demo hello
:结果是:
我们看下Demo类的字节码:
可以看到每一个
invokevirtual
都对应一个 trace结果里的entry。所以,trace实际上是在每一个
invokevirtual
前后插入代码,然后统计调用的时间。trace本身只能拿到当前method的字节码,所以它只能trace当前method里的
invokevirtual
,再深层的invokevirtual
,它并不能知道。The text was updated successfully, but these errors were encountered: