首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android深入卡顿分析与实践

Android深入卡顿分析与实践

作者头像
QQ音乐技术团队
发布于 2023-12-20 03:23:44
发布于 2023-12-20 03:23:44
1.9K0
举报

一、卡顿的相关概念

视觉概念

1、视觉惯性 视觉预期帧率,用户潜意识里认为下帧也应该是当前帧率刷新比如一直60帧,用户潜意识里认为下帧也应该是60帧率。刷新一直是25帧,用户潜意识里认为下帧也应该是25帧率。但是刷新如果是60帧一下跳变为25帧,扰乱用户视觉惯性。这个时候就会出现用户体验的卡顿感。

2、电影帧 电影帧率(18-24),一般是24帧。电影帧单帧耗时:1000ms/24≈41.67ms。电影帧率是一个临界点。低于这个帧率,人眼基本能感觉画面不连续性,也就是感觉到了卡顿。

卡顿概念

1. Google Jank思路

Google Jank 计算思路:考虑视觉惯性,以硬件vsync时间间隔,连续1次vsync没有新画面刷新,则认为是一次卡顿,也就是说下一次vsync时间点没有新画面刷新,则认为是一次Jank

google jank条件较为苛刻

2.PerfDog卡顿原理

  1. 同时满足以下两条件,则认为是一次卡顿Jank. a) 当前帧耗时>前三帧平均耗时2倍。 b) 当前帧耗时>两帧电影帧耗时(1000ms/24*2=84ms)。
  2. 同时满足两条件,则认为是一次严重卡顿BigJank. a) 当前帧耗时>前三帧平均耗时2倍。 b) 当前帧耗时>三帧电影帧耗时(1000ms/24*3=125ms)

电影帧:低于这个帧率,人眼基本能感觉画面不连续性,也就是感觉到了卡顿。

Stutter计算思路:基于PerfDog Jank的基础上,一次Jank卡顿,会有一次卡顿时间Jank time。测试过程中可能有多次Jank卡顿,即有多次卡顿时间Jank time。测试总时长为Time。 PerfDog Stutter(卡顿率) = ∑Jank time / Time

误区:帧率不能直接反映是否卡顿!

FPS的定义:帧率(1秒内平均画面刷新次数)。

平均帧率:传统常说的FPS,1秒内平均画面刷新次数。

帧率FPS高并不能反应流畅或不卡顿。比如:FPS为50帧,前200ms渲染一帧,后800ms渲染49帧,虽然帧率50,但依然觉得非常卡顿。同时帧率FPS低,并不代表卡顿,比如无卡顿时均匀FPS为15帧。所以平均帧率FPS与卡顿无直接关系) 如图

左边非均匀渲染,帧率虽高,但看起来更卡顿

二、卡顿原因有哪些?

1.直接卡顿原因

单点耗时

多点耗时

复杂或频繁执行

2.间接卡顿原因

  1. 主线程分配CPU过少
  2. GC频繁

三、如何排查和定位卡顿?

  1. 工具的选择与使用 工欲善其事必先利其器。我们需要充分理解工具的适用场景,优缺点,合理搭配使用。 1.1 APM监控平台原理

原理:监听Handler消息执行,定时抓栈

优点:可线上使用,查看整体大盘数据,可聚集和搜索,使用成本较低 缺点:52ms阈值过大,性能消耗,小概率误报

1.2 Systrace/CPU Profiler(simpleperf)

公司APM平台无法满足我们所有的需求,由于52ms阈值较大,有一定的误报,还有抓栈本身有一定的性能消耗,线上用户并没有全量开启,因此我们无法保证所有的卡顿问题都被APM抓到了。另外还有个问题是,修改了之后无法立即验证改动效果。

Systrace:

simpleperf

优点:性能消耗很小,使用简单,修改后可立即验证 缺点:只能线下使用,用户卡顿路径无法收集完全

综合分析

主线程占用CPU比率,GC日志,线程数综合分析,后面case举例

四、Wesing中具体Case与解决方案

1.优化效果

经过5.65和5.70版本两次优化,歌房进房卡顿率(PerfDog卡顿率)优化近50%

测试方法:本地验证,进程冷启动,点击开始进房,停留8s待房间UI稳定

测试机型:OnePlus 10 Pro,Android12

2. 典型案例列举与分析

2.1. 复杂任务分析拆解优化

一句话概括:一条Message里面做了太多事情,需要拆分成多条消息优化

case1:歌房采取微服务框架,每个业务有一个独立的Service,由框架派发Activity/Fragment与音视频生命周期,解耦运行,随着业务的增多,所有创建服务和派发生命周期集中在一个消息中运行,造成卡顿严重。

歌房生命周期派发架构图

a.创建微服务实例耗时长达312ms

分析:框架设计之初有考虑到服务不规范使用逐渐会造成卡顿问题,设计了懒加载接口,但由于业务开发者为了便捷,绝大多数都是直接选择进房预加载,导致预加载服务臃肿,卡顿缓慢。

优化方案:将服务进行筛选,不需要预加载的服务改造成懒加载。同时将服务端默认创建为懒加载,如业务需要预加载,需要手动显示设置。

b.handleGameTypeChanged分发耗时长40ms

问题分析:此问题对应“多点耗时”类型场景,这个生命周期方法派发都是需要更新UI界面元素的,因此无法切到子线程派发更新,很容易想到的主线程延迟执行的方法Handler.post(),将当前任务分发到下一个消息执行。

遇到问题:发现主线程有较多消息执行,使得刷新UI的消息执行比较靠后,Ui 刷新出现不顺畅,甚至出现时序问题导致NPE

进一步源码分析:这里分析Handler源码得知postAtFontOfQueue方法可以使得当前消息放到队列最前端,能够保证任务尽可能先执行。如下图源码

最终优化方案:

  1. 任务拆解:将一部分服务的派发放到消息队列的下一个消息中运行,拆解一个消息里面的任务。这里为了保证尽可能少的减少拆解任务带来的时序问题,可以使用postAtFontOfQueue来代替post
  2. 优化房间View层级,降低创建耗时
  3. 按需初始化或延迟初始化View

2.2. 子线程异步加载优化

a.进入歌房初始化音视频sdk 115ms(Running:27ms)

b.操作bitmap模糊背景 103ms

c.主线程解析wns配置的json文件

……

优化方案:切换到线程池中的工作线程进行处理

2.3.预加载优化

case:经过1中复杂任务分解后,发现还是有进房后立即需要使用的服务耗时较长的现象。如下图

类加载过程

分析:通过分析Systrace发现核心服务类加载和验证花费了很多时间,很容易触发“多点耗时”造成卡顿,另外还有NetCore网络单例框架可能造成“单点耗时”卡顿,然而这些类是一进房就立即要使用的,因此无法使用懒加载。此时换一种思路,将类放到子线程进行预加载。

时机:由于预加载类会造成内存占用,那么如果一进入主页就针对所有用户加载的话,可能对那些从来没有加入歌房的用户造成内存紧张,因此,这里针对“时间”和“空间”做一个平衡。仅针对进入过歌房的用户开启,并设置灰度开关

具体方案

在MainTabActivity_doOnCreateAfterLogin里面,针对符合条件的用户需要预加载的类在子线程进行预加载

结果:线上针对进房服务和网络框架的预加载,进房平均耗时大盘数据减少250ms

2.4.懒加载优化

在1中复杂任务拆解时,很容易发生单个任务耗时稍微严重,多个不耗时任务累加就会造成卡顿非常严重,因此针对单个任务中稍微耗时的任务进行懒加载,直到使用时才加载,用以平衡一个消息中的繁多个任务 case1 :成员变量实例懒加载

case2:companion变量配置解析懒加载

case3:成员变量控件解析构造懒加载

case4:进房过程提前拉起子进程7.6ms

…..

共修复类似卡顿问题20+个 优化方案:

1. kotlin提供了一个很好用的by lazy,使用by lazy进行初始化很容易改造懒加载

by lazy源码分析:

可以看到by lazy虽然很好用,但是有加锁操作。因此可以进一步优化,确认无线程安全问题时使用by lazy(LazyThreadSafetyMode.NONE).如:

2.必须在主线程中执行的,延迟到下一个消息执行

2.5.布局层级与按需加载优化

View.inflate涉及IO耗时、反射耗时、构造方法耗时,是一个无法回避的老问题 如图:

方案: 1.针对View层级多的,采用merge标签和动态添加View进行减少View的层级和数量,以减少inflate时长。 2.针对单个View构造耗时长的,优化构造方法和成员变量初始化 3.按需加载,使用ViewStub进行懒加载,如游客模式的布局只需要在游客时进行加载,其他时候无须加载

2.6. 锁耗时优化

case:wesing项目分别使用的火眼日志,Bugly日志,wns日志,sdk内部为确保线程安全,均加锁,造成多线程调用日志框架,非常容易造成卡顿

本地复现

线上堆栈

方案:使用单独日志线程,创建单独HandlerThread,在sdk打印日志之前切换到单独线程,解决锁耗时问题

2.7. 字符串拼接问题优化

case:LogUtil.d打印耗时竟达到18ms

分析:意识里面LogUtil.d不会写入文件,但是我们很容易忽略了方法参数里面的表达式是在方法调用时就执行的,并不是在具体方法执行时运行,所以,项目里面有大量的在日志里面拼接请求参数,序列化json数据等操作,造成了较大的耗时。

解决:集中将日志里面拼接的字符串进行优化,LogUtil.d的日志加上if(isDebug),LogUtil.d以上的对日志拼接做精简和删减。

2.8. 内存问题优化

内存紧张时,系统会频繁GC,造成"stop the world",对卡顿的影响不容小觑

版本水位性能测试时,多次发现歌房进退房存在内存持续增长不释放的问题,导致进房越来越卡,排查后发现有多处内存泄露

case1: 房间内内存泄露问题简要列举

a.弹窗动画未关闭导致泄露,开播聊天房设置背景音乐时,当弹窗关闭时动画没有关闭导致泄露

解决方案:弹窗关播即动画不显示的时候将动画停止并销毁

b.在某一款机型上发现,反复进退歌房,内存会一直增长

解决方案:此类问题应在日常开发中关注APM监控平台(火眼,Bugly)上报修复;系统测试期间针对主路径跑一套完整水位测试,系统性的解决内存泄露

case2:内存优化方案

针对内存紧张时进房间,内容易内存触顶,GC频繁,造成卡顿 分析直播间内使用的ViewPager2作为上下滑动的框架,因此如果能进入当前Item时,不预加载下一个直播,这样就可以避免一个房间对象实例的创建,可以优化较多的内存,缓解卡顿

方案:在内存紧张时侯,设置ViewPager2#setOffscreenPageLimit为1,不同于ViewPager,ViewPager2设置setOffscreenPageLimit为1是有效的,不会预加载下个Item。

结果:经测试同学测试后发现内存优化41M

GC监控建设:

GC日志可以帮助开发查看和分析应用当前的内存使用情况,帮助定位内存泄露,内存抖动问题,以及由于GC导致的卡顿问题,如GC频率过高,非常容易导致卡顿 方案一:自定义一个对象使用弱引用包裹,然后放入自定义的引用队列中,开启一个子线程,循环查看该用于是否被弱引用队列移除。类似LeakCanary监听内存泄露原理

方案二:模仿ActivityThread监听GC,自定义一个弱引用对象,实现其finalize(),当对象要被回收时,说明发生了GC,此时打印一些日志信息

方案二简单有效,无须新建监听线程,最终具体实现

2.9. 线程问题造成的卡顿优化

问题:wesing 5.68版本性能测试,发现线程比上版本多增加了近30个,fd新增250个,卡顿率由15%增加到20%。

分析与排查:经过adb命令排查增量线程,发现增加的是以".tencent.wesing"和"wesing-default-"线程名,没有明显命名特征,退出歌房仍然不减少。排查新版本feature改动,发现升级trtc sdk,利用升级前后apk对比复测,必现。

解决:因此提交给sdk方,由于引入一个业务不相关的功能导致。修复后各项指标正常

疑问:这里新增的线程,跟主线程没有直接关系,为何影响卡顿?

进一步分析:通过perffto sql分析CPU使用情况,发现trtc升级后,DefaultDispatch线程占用超过主线程和RenderThread。

结论: 1.线程增多影响主线程CPU切换时间片时间,从而抢占主线程时间,导致卡顿 2.新增30个线程会显著增加app内存,造成不必要的GC

五、方法与经验总结

优化方法导图

经验总结

1.使用APM平台查询卡顿和ANR问题

业务的卡顿和ANR问题可通过类名或者函数名进行过滤搜索,能更准确地找到问题。也可以根据控制版本查看新增问题

2. 通过Profiler发现卡顿问题&系统性分析问题

CPU Profiler抓取的方法调用trace,在横向上是按时序分布的,可以抓取一个阶段的trace,做横向和纵向的分析及优化

3. 通过日志分析进房过程发生的事件,分析触发时机是否过早,过晚,过慢,或不必要

4.在分析cpu占用过高问题时,可以通过Perftto分析线程cpu时间

Perftto支持sql查询分析,sql模式下,可以通过sql可以算出进程各个线程的cpu时长占用,锁竞争问题

5.通过adb命令分析线程数量

线程过多造成内存增量大,CPU时间抢占,我们通过Perftto发现了trtc线程数量过多导致的内存增长问题

adb shell ps -T | grep xxx

6.分析不合理内存占用问题

通过分析和解决内存泄露以及根据当前内存使用状态采取降级策略,进一步优化内存问题,降低GC频率,整体提升程序性能。

7.版本性能测试

测试同学在系统测试期间会跑性能水位(CPU,内存,FD),但水位波动是表象,开发人员自己也需要针对主路径进行性能复测,根据水位的波动差异做进一步的排查和验证,确认没有漏网之鱼。

8.系统全面地分析问题

直接耗时容易发现和解决,但对于间接耗时如内存问题,CPU占用等问题则隐藏较深,我们既要针对常见的直接耗时问题加以预防和治理,针对间接卡顿和耗时问题也需要做出系统的分析和排查。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-12-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 腾讯音乐技术团队 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【PerfDog专家课堂】APP&游戏需要关注Jank卡顿吗?
导语   本次技术干货分享主要是讲解PerfDog卡顿Jank定义、原理及影响。内容将分为五部分:FrameTime、FPS、流畅度、Jank、影响。从深层次分析在性能测试工作中这五部分起到的重要意义。 第一部分:FrameTime FrameTime 的定义:两帧画面间隔耗时(也可简单认为单帧渲染耗时)。 对于FrameTime和卡顿是否有关联?请看下图的案例图示:   从图中可看出画面中B帧在GPU渲染耗时(帧生成时间)大于显示器刷新间隔,占用两次显示器刷新耗时。也就是说有一次画面没刷新。当出现多
WeTest质量开放平台团队
2019/12/24
3.9K0
【PerfDog专家课堂】APP&游戏需要关注Jank卡顿吗?
APP&游戏需要关注Jank卡顿吗?
    本次技术干货分享主要是讲解PerfDog卡顿Jank定义、原理及影响。内容将分为五部分:FrameTime、FPS、流畅度、Jank、影响。从深层次分析在性能测试工作中这五部分起到的重要意义。
WeTest质量开放平台团队
2020/04/07
1.5K0
APP&游戏需要关注Jank卡顿吗?
IM开发干货分享:万字长文,详解IM“消息“列表卡顿优化实践
本文由融云技术团队原创分享,原题“万字干货:IM “消息”列表卡顿优化实践”,为使文章更好理解,内容有修订。
JackJiang
2021/10/26
1.8K0
Android性能测试——发现和定位内存泄露和卡顿
  因此,对开发的Android应用,必须对其进行性能测试,不然将会直接影响用户体验。
顾翔
2019/12/11
3.2K0
Android性能测试——发现和定位内存泄露和卡顿
PerfDog 下性能测试分析记录(Android)
最近做的项目需要和Unity做交互, Unity作为一款游戏引擎, 还是很耗性能的, 所以找了找性能测试的工具, 发现了腾讯的PerfDog, 记录一下使用心得。
WeTest质量开放平台团队
2020/11/24
1.5K0
PerfDog 下性能测试分析记录(Android)
Android卡顿监控系统
Android 由于机型配置和系统的不同,项目复杂App场景丰富,代码多人参与迭代历史较久等,实际测试时候也会偶尔发现某些业务场景发生卡顿的现象...
likunhuang
2018/07/03
7.9K3
Android卡顿监控系统
性能优化测试中的相关名词
当一个APP或游戏各种功能越来越多时,性能优化的重要性就不言而喻了,况且现在APP或游戏的功能逐渐趋同,提升用户体验已从产品设计本身转到了APP或游戏的流畅性上,这也让越来越多的开发者更加关注性能优化与测试。前段时间PerfDog研发团队曾带来《腾讯游戏性能实战案例分享之帧率陡变1.0》和《APP&游戏需要关注Jank卡顿吗?》两篇关于帧率与Jank的专业分析文章,本次我们就来看看在性能优化测试中会遇到的哪些名词。
WeTest质量开放平台团队
2020/04/27
3.1K0
性能优化测试中的相关名词
Matrix TraceCanary -- 初恋·卡顿
Baby 不要再哭泣,这一幕多么熟悉~ 在使用 App 时,有些人遇上这弹框应该会是一本正经,而有些人看到了估计一脸懵逼(黑人❓)。当然,这里我们要讨论的不是什么初恋,而是对大多数开发者来说,戏虐你千百遍,回头对它如初恋的卡顿。 曾经有篇杂志说“使用一款应用,犹如谈一场恋爱”,当时我觉得这是一本正经地在胡说八道,你手机装了上百款应用,能说这像谈恋爱?但现在想想,其实并非没有道理,当你喜欢上一款应用,往往是因为它的功能足够吸引你,就像你喜欢他的外表,再然后你体验了一段时间(交往),发现这款确实是你喜欢的
微信终端开发团队
2019/01/11
4.4K0
Matrix TraceCanary -- 初恋·卡顿
Android 中的卡顿丢帧原因概述 - 系统篇
在Android 中的卡顿丢帧原因概述 - 应用篇[1]这篇文章中我们列举了应用自身原因导致的手机卡顿问题 , 这一篇文章我们主要列举一些由 Android 平台自身原因导致的卡顿问题. 各大国内 Android 厂商的产品由于硬件性能有高有低 , 功能实现各有差异 , 团队技术能力各有千秋 , 所以其系统的质量也有高有低 , 这里我们就来列举一下 , 由于系统的硬件和软件原因导致的性能问题.
字节流动
2021/04/23
3.6K0
Android 中的卡顿丢帧原因概述 - 系统篇
PerfDog使用说明书
English User's Guide:https://bbs.perfdog.qq.com/article-detail.htmlid=7
WeTest质量开放平台团队
2020/12/08
2.7K0
《广研Android卡顿监控系统》
实现背景 应用的使用流畅度,是衡量用户体验的重要标准之一。Android 由于机型配置和系统的不同,项目复杂App场景丰富,代码多人参与迭代历史较久,代码可能会存在很多UI线程耗时的操作,实际测试时候也会偶尔发现某些业务场景发生卡顿的现象,用户也经常反馈和投诉App使用遇到卡顿。因此,我们越来越关注和提升用户体验的流畅度问题。 已有方案 在这之前,我们将反馈的常见卡顿场景,或测试过程中常见的测试场景使用UI自动化来重复操作,用adb系统工具观察App的卡顿数据情况,试图重现场景来定位问题。 常用的方式是使用
腾讯Bugly
2018/03/23
4.7K2
APP性能测试—PerfDog
PerfDog是一个移动全平台Android/iOS性能测试、分析工具。可以快速定位分析性能问题。手机无需ROOT/越狱,手机硬件、游戏及应用APP也无需做任何修改,极简化即插即用。
清风穆云
2021/08/09
4.3K0
APP性能测试—PerfDog
WeTest明星工具-移动端性能测试PerfDog初探
在十一月初,腾讯就官宣了一则消息,腾讯WeTest明星工具-PerfDog面向全球发布。官宣介绍如下:https://wetest.qq.com/lab/view/475.html。我在看到该新闻时,有种大开眼界的感觉,移动端的性能测试原来可以这么简单。今天闲暇之余,来了一波初探,简单体验了一番。
WeTest质量开放平台团队
2020/09/08
1.3K0
移动端性能测试必备工具PerfDog性能狗
在项目研发支持过程中,经历如上障碍和痛苦。我们决定做一个完全独立、简单易用,与APP版本、系统版本、系统平台无任何关系的性能平台。
WeTest质量开放平台团队
2020/09/01
2.8K0
Android性能优化(六)之卡顿那些事
对普通用户而言,类如内存占用高、耗流量、耗电量等性能问题可能不会轻易发现,但是卡顿问题用户一定会立马直观的感受到。本文就带你一览卡顿的发生、检测、及优化。
用户2898788
2018/08/21
1.2K0
Android性能优化(六)之卡顿那些事
前端性能优化--卡顿篇
前面我有给大家整体地讲过《前端性能优化--归纳篇》,其实里面已经囊括了大多数场景下的一些性能优化的方向。
被删
2024/01/19
6061
前端性能优化--卡顿篇
iOS卡顿优化
图像的显示可以理解为先经过CPU的计算、排版、编解码等操作,然后交有GPU去完成渲染放入缓冲中,当视频控制器受到vSync时会从缓冲中读取已经渲染完成的帧并显示到屏幕上。
莫空9081
2021/02/27
3.9K0
抖音滑动卡顿终极解决方案:从源码逆向推导ViewCacheExtension的3个致命误区
大家好,我是稳稳,一个曾经励志用技术改变世界,现在为随时失业做准备的中年奶爸程序员,与你分享生活和学习的点滴。
AntDream
2025/03/31
2120
抖音滑动卡顿终极解决方案:从源码逆向推导ViewCacheExtension的3个致命误区
腾讯文档表格卡顿指标探索之路
像腾讯文档这样的大型前端应用,面临的卡顿问题比常规前端页面要频繁得多。但卡顿本身难以监测,即使检测到卡顿的发生,也常常难以快速定位,更别提说想要了解大盘的用户真实体验。
被删
2024/10/24
2.9K1
腾讯文档表格卡顿指标探索之路
初识PerfDog
小编最近刚接触了一款性价比较高的性能评测工具-PerfDog,这是腾讯旗下的一款移动全平台iOS/Android性能测试及指标分析工具平台,简而言之就是测试采集手机在运行App时的性能指标数据:FPS、Jank、FTime、CPU、GPU、Memory、Battery 、Network、CTemp等性能参数,从而快速定位分析App的性能问题,小编在这里主要介绍下相关名词含义、使用技巧及案例分析。
用户5521279
2020/12/11
3.1K0
初识PerfDog
相关推荐
【PerfDog专家课堂】APP&游戏需要关注Jank卡顿吗?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档