Android studio Profiler 来监控卡顿实战

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的渲染长了几倍。找这个页面的方法,继续定位,将这个耗时方法处理。

启动卡顿优化

选择CPU记录配置 Trace Java Methods


将start recording cpu activity onstartup,并选中Trace Java Methods,可以启动的时候自动进行record。

设置好了之后就启动Profile

当你看到自己APP,CPU的使用率比较低的时候,差不多就是启动完成了,点一下stop。


Memory Profiler

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

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

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

3.3 捕获堆转储

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

  • 应用已分配哪些类型的对象,以及每个类型分配多少。
  • 每个对象正在使用多少内存。
  • 在代码中的何处仍在引用每个对象。
  • 对象所分配到的调用堆栈。 (目前,如果在记录分配时捕获堆转储,则只有在 Android 7.1 及更低版本中,堆转储才能使用调用堆栈。)

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容