Android技术知识Android开发Android开发

Android studio Profiler 来监控卡顿实战

2023-11-12  本文已影响0人  奔跑吧李博

Android Profiler能够提供关于应用 CPU、内存和网络的实时数据。

卡顿制造
    override fun onBindViewHolder(holder: VideoViewHolder, position: Int) {
        blockFun()
        ...
    }

    /**
     * 卡顿耗时方法
     */
    fun blockFun() {
        Thread.sleep(800) //利用sleep来模拟真实场景中耗时的代码
    }

我在列表视频播放的adapter中插入了sleep(800)毫秒的代码,以对列表滑动造成卡顿,结果真的就卡顿了。
假设我们现在不知道哪里代码有卡顿,通过CPU Profiler来定位解决。

CPU profiler

打开CPU profiler

1.连接真机或虚机设备,确保可以进行ADB调试,依次选择 View > Tool Windows > Profiler 或点击工具栏中的 Profile 图标。
2.当APP运行起来后,点击 CPU 时间轴上的任意位置以打开 CPU Profiler。

CPU Profiler视图介绍

1.事件时间轴:显示应用中的 Activity 在其生命周期内不断转换而经历各种不同状态的过程,并指示用户与设备的交互,包括屏幕旋转事件。如需了解如何在搭载 Android 7.1(API 级别 25)及更低版本的设备上启用事件时间轴,请参阅启用高级分析。

2.CPU 时间轴:显示应用的实时 CPU 使用率(以占总可用 CPU 时间的百分比表示)以及应用当前使用的线程总数。此时间轴还显示其他进程(如系统进程或其他应用)的 CPU 使用率,以便您可以将其与您应用的使用率进行对比。您可以通过沿时间轴的水平轴移动鼠标来检查历史 CPU 使用率数据。

3.线程活动时间轴:列出属于应用进程的每个线程,并使用下面列出的颜色在时间轴上指示它们的活动。记录跟踪数据后,您可以从此时间轴上选择一个线程,以在跟踪数据窗格中检查其数据。

绿色:表示线程处于活动状态或准备使用 CPU。也就是说,它处于正在运行或可运行状态。
黄色:表示线程处于活动状态,但它正在等待一项 I/O 操作(如磁盘或网络 I/O),然后才能完成它的工作。
灰色:表示线程正在休眠且没有消耗任何 CPU 时间。当线程需要访问尚不可用的资源时,有时会发生这种情况。在这种情况下,要么线程自主进入休眠状态,要么内核将线程置于休眠状态,直到所需的资源可用。

记录跟踪数据

左边菜单可以选择method trace 和 method sample,然后点击record进行一段时间的记录分析。


1、Trace Java Methods
会记录每个方法的时间、CPU信息。对运行时性能影响较大。
2、Sample Java Methods
相比于Trace Java Methods会记录每个方法的时间、CPU信息,它会在应用的Java代码执行期间频繁捕获应用的调用堆栈,对运行时性能的影响比较小,能够记录更大的数据区域。

跟踪 Java 方法:在运行时检测应用,以在每个方法调用开始和结束时记录一个时间戳。系统会收集并比较这些时间戳,以生成方法跟踪数据,包括时间信息和 CPU 使用率。

找到这些布局加载耗时,或者第三放库初始化,或者我们自己的方法比较耗时,主要的处理思路就是合理的使用异步初始化、延迟初始化、懒加载机制。

CPU Profiler 显示了正在进行的记录的状态、持续时间和类型:


记录和检查函数跟踪

① 选择时间范围: 确定要在跟踪窗格中检查所记录时间范围的哪一部分。 当首次记录函数跟踪时,CPU Profiler 将在 CPU 时间线中自动选择完整长度。 如果想仅检查所记录时间范围一小部分的函数跟踪数据,可以点击并拖动突出显示的区域边缘以修改其长度。

② 跟踪窗格: 用于显示所选的时间范围和线程的函数跟踪数据。

③ 通过调用图表、火焰图、 Top Down 树或Bottom Up 树的形式显示函数跟踪。

CPU Profile各查看方法比较:


④ 确定如何测量每个函数调用的时间信息:

Wall clock time:实际经过的时间。
Thread time:实际经过的时间减去线程没有消耗 CPU 资源的时间。

使用 Call Chart 标签检查跟踪

Call Chart 标签提供函数跟踪的图形表示形式,其中,水平轴表示函数调用(或调用方)的时间,并沿垂直轴显示其被调用者。 对系统 API 的函数调用显示为橙色,对应用自有函数的调用显示为绿色,对第三方 API(包括 Java 语言 API)的函数调用显示为蓝色。 下图展示了一个调用图表示例:

使用 Flame Chart 标签检查跟踪

Flame Chart 标签提供一个倒置的调用图表,用来汇总完全相同的调用堆栈。也就是说,将具有相同调用方顺序的完全相同的方法或函数收集起来,并在火焰图中将它们表示为一个较长的横条(而不是将它们显示为多个较短的横条,如调用图表中所示)。这样更方便您查看哪些方法或函数消耗的时间最多。不过,这也意味着,水平轴不代表时间轴,而是表示执行每个方法或函数所需的相对时间量。

这里卡顿监测的数据:
选中左侧的main线程,看main线程执行了哪些函数


各个方法调用的总时长,就用横条的长度来表示的,横条长度越长,表示这个方法在这段时间占用的时间越长。然后从下往上依次找,找时长较长并且是我们项目自写的函数,而不是系统函数的调用。


继续往上,然后发现在这个VideoAdapter的onBindViewHolder方法中,调用了blockFun方法,内部因为调用了sleep方法,导致这个方法总共占用了6.4s的长度。
接下来就是解决这个问题了,可以利用协程切子线程去完成这个sleep方法,然后使用withContext切回主线程,解决卡顿!

    /**
     * 卡顿耗时方法
     */
    fun blockFun() {
        GlobalScope.launch {
            Thread.sleep(800) //模拟的平时开发耗时操作

            withContext(Dispatchers.Main) {
                
            }
        }
    }
界面卡顿监测

在展示图片页面ShowImageActivity进入时加了Thread.sleep(800),以模拟真实项目中的卡顿情况。

class ShowImageActivity : BaseBindingActivity<ActivityShowImageBinding>({ActivityShowImageBinding.inflate(it)}) {

    override fun init() {
        binding.ivHead.setOnClickListener { v: View? -> finish() }
        val headRes = intent.getIntExtra("res", 0)
        binding.ivHead.setImageResource(headRes)
    }

    override fun onResume() {
        super.onResume()

        blockFun()
    }

    /**
     * 卡顿耗时方法
     */
    fun blockFun() {
        Thread.sleep(800)
    }
}

出现卡顿通常是因为界面线程(在大多数应用中,它是主线程)上存在一些减速或阻塞异步调用。您可以利用系统轨迹(System Trace Recording)找出问题所在。选择System Trace,进行操作中的记录,结束后得到绘制结果。

Frames:此部分显示应用中的界面线程和RenderThread轨迹事件。时长超过 16毫秒的事件会以红色表示,以突出显示潜在的卡顿帧,因为它们超出了以 60 帧/秒 (fps) 的速度进行呈现的截止时间。那么就找渲染表示为红色帧,查看这些红色集中的帧的真实时长。


结果找到这些渲染时长过长的为ShowImageActivity页面,比如这里耗时59ms,比正常16ms的渲染长了几倍。找这个页面的方法,继续定位,将这个耗时方法处理。

Memory Profiler

Memory Profiler 是可帮助识别导致应用卡顿、冻结甚至崩溃的内存泄漏和流失。 它显示一个应用内存使用量的实时图表,可以捕获堆转储、强制执行垃圾回收以及跟踪内存分配。

默认情况下,左侧的分配列表按类名称排列。 在列表顶部,可以使用右侧的下拉列表在以下排列方式之间进行切换:

Arrange by class:基于类名称对所有分配进行分组。
Arrange by package:基于软件包名称对所有分配进行分组。
Arrange by callstack:将所有分配分组到其对应的调用堆栈。

3.3 捕获堆转储

堆转储显示在捕获堆转储时应用中哪些对象正在使用内存。 特别是在长时间的用户会话后,堆转储会显示您认为不应再位于内存中却仍在内存中的对象,从而帮助识别内存泄漏。 在捕获堆转储后,可以查看以下信息:

要捕获堆转储,在 Memory Profiler 工具栏中点击 Dump Java heap 。

参考:
https://blog.csdn.net/u011578734/article/details/109496667
https://www.jianshu.com/p/0770cde09ede

上一篇 下一篇

猜你喜欢

热点阅读