在Android Studio中使用Method trace,查看某进程的所有线程trace的方法

时间:2024-05-22 21:02:45

转自:https://segmentfault.com/a/1190000011084104

背景


近几天开发的过程中,遇到了一个很棘手的问题:在没网络情况下OKHttp的任何请求,全都没有任何回应。想要查看线程的调用栈查看是哪里stuck了。


于是使用了AndroidStudio的工具。Monitors中CPU的Method tracing功能。这就是今天写这篇文章的目的。

在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
(Android Studio的Method tracing功能)

Method tracing有什么作用?


Method tracing的作用就是监听一段时间内,某个进程的某个线程,执行的所有方法,以及各个方法所消耗的时间。然后开发者可以从中找到一些蛛丝马迹来推断出程序中的一些问题。

如何使用?


  1. 按下“start method tracing”按钮。如图:

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法

  2. 对app进行想要监听过程的操作。我这里就是操作异常的网络请求。

  3. 按下“stop method tracing”按钮。如图:

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法

  4. 查看生成的trace文件。

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (这就是分析出来的method trace文件)

trace文件怎么分析?


  1. 线程选择。
    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (主线程)
    线程下拉框拉下来以后出来一堆线程。其中“main”就是主线程。

  2. x时间轴选择。

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (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。


  3. method图标,重头戏来了,整个trace中最重要的就是这个图标了

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (Arrays.copyOf方法的调用详情)


    首先,最显眼的东西就是这个黄色的长条条了,每个长方形都是一个方法,长度代表这个方法执行的时间(就是上面咱们选择的Wall Clock Time啦)。Inclusive Time是指copyOf以及它的子方法调用的时间,占整个线程执行时间的占比。Exclusive Time与Inclusive Time相对,它不统计子方法执行的时间。


    进一步分析,copyOf长方形的的上面的方法是ArrayList.grow方法,下面的长方形是...嗯也是一个copyOf。其实这个上下关系,就正是父子关系。即copyOf是ArrayList.grow的一个子方法。


    那...我们其实根本不想分析这些很细节的方法,我们只关心我们自己写的方法的调用顺序或者调用耗时。那该怎么做呢?


    例如说,我原本的目的其实是查看被stuck的网络请求。我可以从中得到什么信息?首先,我查看的是自己写的方法,并非底层的方法,那么我要查看的长方形就在上面。其次,我想查看的是stuck的方法,那么它最终一定没有执行完毕,那么我要查看的长方形一定在最后。


    那么,选中想要的线程,拉到最后:

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (最后的横截面)


    这个最后的横截面,就是没有执行完的方法的调用栈。再看最后一个长方形:

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (libcore.io.Posix.android_getaddrinfo)

    那么这个线程最终卡在了这一步。至此,我达到了我的目的。


  4. 最后,还有下面的一个表格:

    在Android Studio中使用Method trace,查看某进程的所有线程trace的方法
    (方法统计表格)
    有四栏数据,分别是:方法名称,方法调用次数,包含子方法的调用时间,不包含子方法的调用时间。


总结一下


其实一开始写这篇文章之前,Method tracing的好多功能我都不知道是什么。想着要记录一下终于使用这个工具达到了我的目的,然后记录下来这个过程。写文章的过程中,反而发现很多东西都不懂,这就需要去查资料。结果就真的查出了好多恍然大悟的知识点。每次写完一篇文章都收获很大,要告诉自己记住这样的感觉,以后有所收获一定要不怕麻烦,把它换成文字,一来记录自己的所得,二来可以梳理这些知识点,甚至有时候可以得到写文章以前不知道的东西。