Android开发高手课
张绍文
前微信高级工程师,Tinker负责人
立即订阅
12609 人已学习
课程目录
已完结 61 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 焦虑的移动开发者该如何破局?
免费
导读 (1讲)
导读 | 如何打造高质量的应用?
模块一 高质量开发 (25讲)
01 | 崩溃优化(上):关于“崩溃”那些事儿
02 | 崩溃优化(下):应用崩溃了,你应该如何去分析?
03 | 内存优化(上):4GB内存时代,再谈内存优化
04 | 内存优化(下):内存优化这件事,应该从哪里着手?
05 | 卡顿优化(上):你要掌握的卡顿分析方法
06 | 卡顿优化(下):如何监控应用卡顿?
06补充篇 | 卡顿优化:卡顿现场与卡顿分析
07 | 启动优化(上):从启动过程看启动速度优化
08 | 启动优化(下):优化启动速度的进阶方法
09 | I/O优化(上):开发工程师必备的I/O优化知识
10 | I/O优化(中):不同I/O方式的使用场景是什么?
11 | I/O优化(下):如何监控线上I/O操作?
12 | 存储优化(上):常见的数据存储方法有哪些?
13 | 存储优化(中):如何优化数据存储?
14 | 存储优化(下):数据库SQLite的使用和优化
15 | 网络优化(上):移动开发工程师必备的网络优化知识
16 | 网络优化(中):复杂多变的移动网络该如何优化?
17 | 网络优化(下):大数据下网络该如何监控?
18 | 耗电优化(上):从电量优化的演进看耗电分析
19 | 耗电优化(下):耗电的优化方法与线上监控
20 | UI 优化(上):UI 渲染的几个关键概念
21 | UI 优化(下):如何优化 UI 渲染?
22 | 包体积优化(上):如何减少安装包大小?
23 | 包体积优化(下):资源优化的进阶实践
24 | 想成为Android高手,你需要先搞定这三个问题
模块二 高效开发 (9讲)
25 | 如何提升组织与个人的研发效能?
26 | 关于编译,你需要了解什么?
27 | 编译插桩的三种方法:AspectJ、ASM、ReDex
28 | 大数据与AI,如何高效地测试?
29 | 从每月到每天,如何给版本发布提速?
30 | 数据评估(上):如何实现高可用的上报组件?
31 | 数据评估(下):什么是大数据平台?
32 | 线上疑难问题该如何排查和跟踪?
33 | 做一名有高度的移动开发工程师
模块三 架构演进 (9讲)
34 | 聊聊重构:优秀的架构都是演进而来的
35 | Native Hook 技术,天使还是魔鬼?
36 | 跨平台开发的现状与应用
37 | 移动开发新大陆:工作三年半,移动开发转型手游开发
38 | 移动开发新大陆:Android音视频开发
39 | 移动开发新大陆: 边缘智能计算的趋势
40 | 动态化实践,如何选择适合自己的方案?
41 | 聊聊Flutter,面对层出不穷的新技术该如何跟进?
42 | Android开发高手课学习心得
练习Sample跑起来 (8讲)
练习Sample跑起来 | 热点问题答疑第1期
练习Sample跑起来 | 热点问题答疑第2期
练习Sample跑起来 | 热点问题答疑第3期
练习Sample跑起来 | 热点问题答疑第4期
练习Sample跑起来 | ASM插桩强化练习
练习Sample跑起来 | 唯鹿同学的练习手记 第1辑
练习Sample跑起来 | 唯鹿同学的练习手记 第2辑
练习Sample跑起来 | 唯鹿同学的练习手记 第3辑
特别放送 (7讲)
Android JVM TI机制详解(内含福利彩蛋)
专栏学得苦?可能是方法没找对
专栏学得苦?可能你还需要一份配套学习书单
Native下如何获取调用栈?
聊聊Framework的学习方法
Android工程师的“面试指南”
程序员修炼之路 | 设计能力的提升途径
结束语 (1讲)
结束语 | 移动开发的今天和明天
Android开发高手课
登录|注册

06补充篇 | 卡顿优化:卡顿现场与卡顿分析

张绍文 2018-12-18
我们使用上一期所讲的插桩或者 Profilo 的方案,可以得到卡顿过程所有运行函数的耗时。在大部分情况下,这几种方案的确非常好用,可以让我们更加明确真正的卡顿点在哪里。
但是,你肯定还遇到过很多莫名其妙的卡顿,比如读取 1KB 的文件、读取很小的 asset 资源或者只是简单的创建一个目录。
为什么看起来这么简单的操作也会耗费那么长的时间呢?那我们如何通过收集更加丰富的卡顿现场信息,进一步定位并排查问题呢?

卡顿现场

我先来举一个线上曾经发现的卡顿例子,下面是它的具体耗时信息。
从图上看,Activity 的 onCreate 函数耗时达到 3 秒,而其中 Lottie 动画中openNonAsset函数耗时竟然将近 2 秒。尽管是读取一个 30KB 的资源文件,但是它的耗时真的会有那么长吗?
今天我们就一起来分析这个问题吧。
1. Java 实现
进一步分析 openNonAsset 相关源码的时候发现,AssetManager 内部有大量的 synchronized 锁。首先我怀疑还是锁的问题,接下来需要把卡顿时各个线程的状态以及堆栈收集起来做进一步分析。
步骤一:获得 Java 线程状态
通过 Thread 的 getState 方法可以获取线程状态,当时主线程果然是 BLOCKED 状态。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《Android开发高手课》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(23)

  • 郭威
    问一下作者那个fork获取线程堆栈的方式说的太笼统了,有小demo么

    作者回复: 先留时间给大家实现,后续看情况要不要放出来

    2018-12-19
    6
  • 李鑫鑫
    感觉我在浪费生命!每天写view!原来安卓还有这么好玩的东西!
    2018-12-18
    2
  • 小美
    绍文老师 ,android 系统里面没有 jstack 要如何dump 出 thread 信息呢?麻烦老师指导下~
    2018-12-18
    2
  • Geek_2d38e3
    张老师,请教一下,黑科技手机线程堆栈那个方案,我成功调用了DumpState函数,但是函数执行完毕后,传入的std::ostream里面没有内容,您有遇到过这种情况吗?
    2019-07-18
    1
  • X
    老师好,工作中的确遇到过类似开篇描述的卡顿现场,只不过当时是操作一个三方数据库,主线程里初始化了数据库有关的实体对象,然后又进行了数据库异步查找,结果ANR. 查看源码发现,两个操作都用的该数据库核心类的类锁,导致主线程一直等待子线程是释放锁。这个不是线上的,是线下的,所以查找很快,解决方式是把把异步查找用handler post了一个runnable去操作,确保主线程初始化该数据库的操作在这个异步查找之前,即先得到锁。
    所以这里顺便问下:
    1.上述线程抢占导致的ANR处理方法是否妥当?
    2. 文中说到SIGQUIT性能差,那个不是模仿系统ANR机制么 ,而那个黑科技黑科技也是模仿ANR日志打印,为何就比前者好呢?
    3.另外想问下那个文中提到的抽样是客户端控制还是服务端控制的啊?

    作者回复: 1. 数据库要case by case
    2. Sigquit是卡在当前进程操作,黑科技是卡在子进程操作
    3. 服务端

    2018-12-18
    1
  • Tony
    老师我想问下应用自己不适用JNI层代码去fork子进程,使用android上层框架,比如java或者Kotlin语言的api如何fork应用的子进程出来,网上也看了一些,都是通过JNI层c++代码去fork的
    2019-11-14
  • 薯条
    学习了,坚持打卡,走完整个课程
    2019-09-22
  • 朱刚
    案例的最终解决方案呢
    2019-09-22
  • 1874
    老师好,通过breakpad方案获取native堆栈时能关联上java层的堆栈吗?thread id是对应不上的。根据threadname?c层子线程要是没命名应该会有很多重复吧,期待老师解答
    2019-05-16
  • 1874
    老师好,在native层hook子进程获取java堆栈的Demo能放出来吗?期待

    作者回复: 主要是通过Hook跟日志,定位是哪些view的问题

    2019-03-27
  • catkin
    张老师,文中说的fork进程收集,但是在高版本中好像fork出来的进程不能执行啊!

    作者回复: 什么意思?fork机制在很多场景都有使用,android系统也是这样。

    2019-02-22
  • sjx
    项目中使用的lottie,CPU占用非常高,大家有什么解决方案吗?

    作者回复: 需要进一步拆解下去具体的原因,是哪些步骤耗时

    2019-01-05
  • Juinn
    shaowen老师,课后作业中,hook线程的创建,为什么只有在sample进程有效,so库不是共享的吗

    作者回复: plt hook只能hook本进程的,对其他进程是无效的

    2019-01-01
  • Juinn
    shaowen老师,此章节的例子是基于有卡顿树情况下,再去分析,那么这个卡顿树怎么获取?

    作者回复: 收集卡顿堆栈,然后在后台根据堆栈聚合得到的

    2019-01-01
  • Fred
    老师好,在应用开发时发现同一个方法,拥有相同的输入参数,在不同的Activity里面执行的耗时会不一样。对于这个问题应该从那些角度去分析呢?

    作者回复: 通过第七章systrace的方法可以分析具体的差异情况

    2018-12-25
  • Geek_295233
    实践见真理,开阔了视野
    2018-12-24
  • Sean
    文中说明的 " 需要注意的是在 Android 7.0 之后,getAllStackTraces 是不会返回主线程的堆栈的",我在8.0和8.1的系统下Java 层通过代码测试过,发现主线程的stacktrace实际上是可以得到的。不知所述结论是如何得到的?

    作者回复: 这里笔误了,应该是Android 7.0,没有之后。我后面改一下

    2018-12-23
  • 欧哩給
    老师,关于Android的内存管理与GC,有推荐的书籍或者博客吗?
    2018-12-20
  • 废帅
    现在学的还是糊涂的,先坚持打卡吧
    2018-12-19
  • null
    老师,我主线程调用 synchronized时,显示的是Monitor状态,查过之后,"Monitor" is the BLOCKED state,只是名字不同,实际是一种状态是吗?

    作者回复: 要看具体版本跟代码

    2018-12-19
收起评论
23
返回
顶部