转自:https://segmentfault.com/a/1190000011084104
背景
近几天开发的过程中,遇到了一个很棘手的问题:在没网络情况下OKHttp的任何请求,全都没有任何回应。想要查看线程的调用栈查看是哪里stuck了。
于是使用了AndroidStudio的工具。Monitors中CPU的Method tracing功能。这就是今天写这篇文章的目的。
(Android Studio的Method tracing功能)
Method tracing有什么作用?
Method tracing的作用就是监听一段时间内,某个进程的某个线程,执行的所有方法,以及各个方法所消耗的时间。然后开发者可以从中找到一些蛛丝马迹来推断出程序中的一些问题。
如何使用?
-
按下“start method tracing”按钮。如图:
-
对app进行想要监听过程的操作。我这里就是操作异常的网络请求。
-
按下“stop method tracing”按钮。如图:
-
查看生成的trace文件。
(这就是分析出来的method trace文件)
trace文件怎么分析?
-
线程选择。
(主线程)
线程下拉框拉下来以后出来一堆线程。其中“main”就是主线程。
-
x时间轴选择。
(x时间轴)
关于时间轴的解释,我查了下google:Wall Clock Time - Total CPU time elapsed between the method call and return.
Thread Time - Total time during which the JRE scheduled the thread during call processing. It’s less than or equal to the Wall Clock Time: less if the JRE interrupted the thread, and equal if it didn’t. The thread might not run continuously; when it’s not executing, that time is excluded. If threads are interrupted often and it’s not by design, the interruptions affect app performance. However, an example of a by-design use is synchronous operations that take a long time, such as file transfers and reads from disk, where the method could be the asynchronous wrapper for the synchronous reader.
大致理解一下:
Wall Clock Time,计算整个CPU时间,一个方法从开始到return,都会计算在内。
Thread Time,从整个CPU时间,减掉可能由JRE中断线程的时间。OK这里就选择Wall Clock Time。
-
method图标,重头戏来了,整个trace中最重要的就是这个图标了
(Arrays.copyOf方法的调用详情)
首先,最显眼的东西就是这个黄色的长条条了,每个长方形都是一个方法,长度代表这个方法执行的时间(就是上面咱们选择的Wall Clock Time啦)。Inclusive Time是指copyOf以及它的子方法调用的时间,占整个线程执行时间的占比。Exclusive Time与Inclusive Time相对,它不统计子方法执行的时间。
进一步分析,copyOf长方形的的上面的方法是ArrayList.grow方法,下面的长方形是...嗯也是一个copyOf。其实这个上下关系,就正是父子关系。即copyOf是ArrayList.grow的一个子方法。
那...我们其实根本不想分析这些很细节的方法,我们只关心我们自己写的方法的调用顺序或者调用耗时。那该怎么做呢?
例如说,我原本的目的其实是查看被stuck的网络请求。我可以从中得到什么信息?首先,我查看的是自己写的方法,并非底层的方法,那么我要查看的长方形就在上面。其次,我想查看的是stuck的方法,那么它最终一定没有执行完毕,那么我要查看的长方形一定在最后。
那么,选中想要的线程,拉到最后:
(最后的横截面)
这个最后的横截面,就是没有执行完的方法的调用栈。再看最后一个长方形:
(libcore.io.Posix.android_getaddrinfo)那么这个线程最终卡在了这一步。至此,我达到了我的目的。
-
最后,还有下面的一个表格:
(方法统计表格)
有四栏数据,分别是:方法名称,方法调用次数,包含子方法的调用时间,不包含子方法的调用时间。
总结一下
其实一开始写这篇文章之前,Method tracing的好多功能我都不知道是什么。想着要记录一下终于使用这个工具达到了我的目的,然后记录下来这个过程。写文章的过程中,反而发现很多东西都不懂,这就需要去查资料。结果就真的查出了好多恍然大悟的知识点。每次写完一篇文章都收获很大,要告诉自己记住这样的感觉,以后有所收获一定要不怕麻烦,把它换成文字,一来记录自己的所得,二来可以梳理这些知识点,甚至有时候可以得到写文章以前不知道的东西。