ARTHook实战 小结 项目GitHub 背景介绍 前面提到过两种自动化自动化检测方案: AndroidPerformanceMonitor和ANR-WatchDog; 需要本方案的原因:自动化卡顿检测方案无法满足所有场景 ; 如,有很多Message要执行, 但是所有Message的时间, 都没有达到自动化卡顿检测方案所配置的卡顿的判定阈值, 那这种情况,自动化卡顿检测方案对这些“较小型”的卡顿问题便无能为力了; 可是这些没有达到卡顿的判定阈值的“较小型”的卡顿问题, 却会一直影响用户体验,这显然是不行的!! 需要建立体系化的卡顿解决方案, 便要尽早地尽可能多地暴露问题,补充已有方案的不足; ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 需要关注的单点问题 View绘制等; 下面以主线程IPC为例, 因为IPC其实是一个很耗时的操作, 但实际开发时很多时候都没有得到足够的重视, 偶尔还会在主线程进行IPC操作,以及频繁的调用, 而这种耗时其实很少达到卡顿的阈值
AndroidPerformanceMonitor implementation 'com.github.markzhai:blockcanary-android:1.5.0' AndroidPerformanceMonitor 是一个检测卡顿的开源库 而其使用与LeakCanary也比较相似,可以自主设置卡顿检测时间,检测到的卡顿同样是以Notification展示,在使用体验上也相当类似,与LeakCanary可以说是孪生兄弟。 提示框(Room表现不一,有些手机厂商会把提示框给去掉) ANR 解决方式 adb pull data/anr/traces.txt存储路径,然后分析CPU、IO及锁 ANR 测试 //给主线程造成卡顿 检测组件 https://github.com/SalomonBrys/ANR-WatchDog 使用:new ANRWatchDog().start(); 原理 ANR-WatchDog同样是一个检测卡顿的检测库 AndroidPerformanceMonitor与 ANR-WatchDog 区别 AndroidPerformanceMonitor:监控Msg ANR-WatchDog:看最终结果 前者适合监控卡顿
从网上下载的资源用PS打开有时候会很卡顿以下几个方法可以让PS很丝滑 删除冗余的元数据,如何查看元数据菜单(文件)--文件简介(alt+ctrl+shift+i)--原始数据 有时候会显示meta数据过大无法显示
一、卡顿原因 屏幕1秒60帧,平均每帧16.6毫秒,如果代码实现不佳,或者过于复杂,导致一帧绘制时间大于16.6毫秒,则无法完成绘制,造成丢帧,连续出现掉帧,在现象上表现为卡顿。 默认情况下,性能分析器只会将卡顿帧显示为有待调查的候选对象。在每个卡顿帧中,红色部分突出显示了相应帧超出其渲染截止时间的时长。 image.png 2、在Android 11上检测卡顿情况 对于搭载 Android 11(API 级别 30)的设备,CPU 性能分析器的 Frame Lifecycle 部分会显示捕获的轨迹。 例如,值 2 表示应用当前处于三重缓冲状态,这会导致额外的输入延迟。 Display 部分会提供有助于检测潜在卡顿的实用信号,例如何时界面线程或 RenderThread 的用时超过 16 毫秒。 这些线程与界面呈现有关,可能是导致卡顿的原因。 如需在 Android 10 或更低版本上检测卡顿情况,请执行以下操作: 查看 Display 中的 Frames 轨迹。
这就是界面卡顿的原因。 所以,卡顿造成的原因分为CPU卡顿和GPU卡顿,CPU卡顿可以用CADisplayLink来检测,UI更新卡顿可以用Runloop的mode来检测 监测卡顿:开一个子线程,利用displaylink或者 Runloop来监测卡顿; 收集堆栈:将卡顿时的堆栈收集起来; 上传记录:将卡顿上传到后台或自定义; 这里我引用一张微信开发团队的监测流程图: 二、Runloop检测卡顿 首先我们来看一个 所以通过比较dispalylink的更新时间就可以知道是否存在卡顿 - (void)updateTime{ if (! 2、上传位置,一种是自己建立后台来统计这些卡顿,嫌麻烦的话是利用第三方平台、如友盟(统计崩溃比较多)、听云、OneApm、博睿,都大同小异。
浏览器访问页面卡顿刷新页面方法 同一个网址在一个浏览器中开了多个tab页窗口,会出现卡顿等转圈圈的现象 扩展浏览器缓存空间 通过修改启动参数增加缓存容量: "C:\Program Files (x86) 要出现❌,以后,先点一下❌,再右击出现3个选项,选最后一个 1.正常重新加载 Ctrl+R 2.硬性重新加载 Ctrl+Shift+R 3.清空缓存并硬性重新加载
按照60FPS的帧率,每隔16ms就会有一次VSync信号,1秒是1000ms,1000/60 = 16 卡顿的原因: iOS默认刷新频率是60HZ,所以GPU渲染只要达到60fps就不会产生卡顿。 RunLoop监听 原理:卡顿是在主线程进行了耗时的操作,可以添加Observer到主线程的Runloop中,通过Runloop状态切换的耗时,达到监控卡顿的目的。 卡顿监控起一个子线程定时检查主线程的状态,当主线程的状态运行超过一定的阈值,则认为主线程卡顿,从而标记为一个卡顿。 分析实现: 使用Runloop进行卡顿监控,定义一个阈值判断卡顿的出现,记录下来上报到服务器。 比如: 主程序Runloop超时的阈值是2秒,子线程的检查周期是1秒,每个1秒,子线程检查主线程的运行状态;如果检查到主线程Runloop的运行超过2秒,则认为是卡顿,并获得当前的线程快照。
青年时代的锻炼比黄金还贵——佚名 今天idea很卡,经常卡死动不了崩溃,明明内存分配了很高,使用率也很低,但还是卡死 最后把所有插件禁用掉,发现不卡了,于是一个插件一个插件启用,直到又出现崩溃
前言 在日常业务测试中经常会发现页面跳转卡顿、滑动卡顿等等卡顿问题,但是往往发生了卡顿问题也没有什么具体信息提供给开发同学排查问题,所以也就不了了之了。 Blockcanary介绍 介绍 Blockcanary是@markzhai开发的检测app主线程卡顿工具,不需要在代码中插桩和debug代码就能检测出卡顿。 log日志 根据上面的配置代码并打包app,进行手工测试如果主线程卡顿超过1000ms,会在手机sdcard/BlockTest目录下生成卡顿日志。 卡顿文件包含几点: 发生时间 版本 imei cpu型号 内存 卡顿堆栈 上报log日志 之前方式的卡顿日志需要连接该设备把log手动导出来分析,或者在卡顿弹框中展示,这样并不能做到日志持久化和做后期的数据分析 项目 我们模拟一个Demo项目来模卡顿,点击block按钮后sleep2秒来模拟卡顿。 卡顿日志:
视频演示:http://mpvideo.qpic.cn/0b2e4yaaiaaaa4alewnoojqvbzwdattaabaa.f10002.mp4? C#中禁止跨线程直接访问控件,InvokeRequired是为了解决这个问题而产生的,当一个控件的InvokeRequired属性值为真时,说明有一个创建它以外的线程想访问它。 btnStartRead.Enabled = true; UiRefresh(null); } 正常运行时: 点击停止读: 正常读,拔掉通讯线,界面不卡:
如图所示,主线程在T1~T2时间段内发生卡顿,上述方案中获取卡顿堆栈的时机已经是T2时刻。 实际卡顿可能是这段时间内某个函数的耗时过大导致卡顿,而不一定是T2时刻的问题,如此捕获的卡顿信息就无法如实反应卡顿的现场。 我们看看在这之前微信iOS主线程卡顿监控系统是如何实现的捕获堆栈。 把一个卡顿抽离成一个关键的堆栈的思路,可以大大降低了数据量, 前面提及60W个堆栈就可以缩减为2W个堆栈(2000*10*1=2W)。 ,按照卡顿上报重复的次数降序列出; 2、归类后展示每个卡顿的关键耗时代码,也可查看全部堆栈内容; 3、支持操作卡顿记录,如搜索卡顿,提tapd单,标注已解决等; 4、展示每个版本的卡顿问题修复数据情况, 所以在切后台时要主动stop monitor,切前台时要重新start 1.组件引入方式 2.主线程卡顿监控的使用方式 1)启动监控 2)停止监控 3)获取卡顿信息 app中加入监控卡顿SDK后
多配置中心,解决无法同步更新(nacos/consul) 问题背景 tomcat部署于linux centos 7.x 安装了jdk1.8和tomat8 发现,每次在启动tomcat的时候都会出现卡顿好久才会完成部署 /www.liangzl.com/get-article-detail-5351.html https://www.shangmayuan.com/a/744bc0087b904d61b5fb28a2.
drawvisual wpf的控件frameworkelement、继承自visual,wpf的gui节点分为 visualtree,可见的ui树 logictree,xaml中的节点树 drawvisual卡顿 drawvisual数量增加后,有时出现卡顿现象,比对分析发现卡顿时的资源情况 drawvisual绘制完成后正确释放,否则大量的资源集中起来会造成绘制卡顿,如下图gc占了很多时间 io写入数据明显增加
丢帧给用户的感觉就是卡顿,而且如果运算过于复杂,丢帧会更多,导致界面常常处于停滞状态。 卡顿原因 过于复杂的布局 界面性能取决于 UI 的渲染性能,UI 渲染的整个过程由 CPU 和 GPU 两个部分协同完成。 如果 UI 布局层次太深,或是自定义控件的 onDraw 中有复杂运算,CPU 的相关运算就可能大于 16ms,导致卡顿。 过度绘制 UI 线程的复杂运算 UI 线程的复杂运算会造成 UI 无响应,导致 ANR,但更多的是造成 UI 响应停滞卡顿,ANR 是卡顿的极致。
什么是卡顿 什么是卡顿,很多人能马上联系到的是帧率 FPS (每秒显示帧数)。那么多低的 FPS 才是卡顿呢?又或者低 FPS 真的就是卡顿吗? 一个稳定在 30FPS 的动画,我们不会认为是卡顿的,但一旦 FPS 很不稳定,人眼往往容易感知到。 FPS 低并不意味着卡顿发生,而卡顿发生 FPS 一定不高。 相比单看平均帧率,掉帧程度的分布可以明显的看出,界面卡顿(平均帧率低)的原因是因为连续轻微的掉帧(下图1),还是某次严重掉帧造成的(下图2)。 ? 一般也是从用户反馈中得到,通常表述为“新版本变卡了”,“朋友圈很卡”,“聊天经常无响应”,我们很难在这种描述中,直接洞察到卡顿的根源,甚至有些连卡顿的场景都不知道,很难准确重现,所以这种卡顿容易让人摸不着头脑 2、为了减少插桩量及性能损耗,通过遍历 class 方法指令集,判断扫描的函数是否只含有 PUT/READ FIELD 等简单的指令,来过滤一些默认或匿名构造函数,以及 get/set 等简单不耗时函数
前言 论坛上有很多帖子、很多人说Creator大项目卡顿,也在苦苦寻找解决方案。 这对于每一个想用Creator做个大项目或者正在做着项目的小伙伴来说都是很难受的。 而项目后期大部分时间可能都是在改代码,也就意味着,一直卡。像吃屎一样。 ? 其实。。。 其实很多引擎在项目资源多的时候都会出现卡顿、反馈时间长等问题,这个是通病。 有问题就解决嘛。 卡顿的根源:Creator编辑器的资源管理机制 Creator编辑器会对所有资源进行分析,记录它们之间的依赖关系。 这也是以下情况的缘由 保存一下prefab,卡顿好久 保存一下代码,切回来卡了好久 正所谓成也萧何败也萧何 解决思路:拆 论坛上其实就有这个思路的方案,比如 将图片预先打成图集=>减少图片资源量 将资源放到 卡顿问题也是可以轻易解决的,不是吗?
项目GitHub 本文要点 一般使用的卡顿优化工具 卡顿问题概述 卡顿问题分析难点 关于CPU Profiler 关于Systrace 关于StrictMode 磁盘读写违例检测实战 实例限制检测实战 一般使用的卡顿优化工具 CPU Profiler Systrace StrictMode (strict adj.精确的; 绝对的; 严格的,严谨的; [植]笔直的 mode n.方式; 状况; 时尚,风尚; 调式 模式;) 卡顿问题概述 很多性能问题(如内存占用高、耗费流量等)都相对不容易被发现, 但是卡顿问题却是很容易被直观感受到的; 卡顿问题较难排查、定位; 卡顿问题分析难点 可能的产生原因 繁杂:代码、内存、绘制、IO、【在主线程做UI处理、IO操作耗时操作】等; 线上卡顿问题,在线下难以复现, 卡顿问题跟用户届时的现场环境有很大的关系; 比如, 届时用户终端的磁盘IO空间不足,影响了 APP的IO写入性能, 导致APP卡顿,这样的场景有时候是很难复现的; 【最好在问题发生时候,就记录下来用户届时的场景】 关于CPU Profiler 图形的形式展示程序的执行时间、调用栈、执行次数等
框架中各个主要类的功能划分 接下来我们讨论一下方案的不足 不足1:确实检测到卡顿,但获取到的卡顿堆栈信息可能不准确; 不足2:和OOM一样,最后的打印堆栈只是表象,不是真正的问题; 我们还需要监控过程中的一次次 【假设初始方案,整个监控周期只采集一次】 如上图, 假设主线程 在时间点T1(开始阻塞)与T2(阻塞结束)之间的时间段中发生了卡顿, 而卡顿检测方案是在T2时刻, 也就是 阻塞时间完全结束 ( 前提是T2-T1大于阈值,确定了是卡顿问题)的时刻, 方案才开始获取卡顿堆栈的信息, 而实际发生卡顿(如发生违例耗时处理过程)的时间点, 可能是在这个时间段内,而非获取信息的T2点, 那有可能 , 耗时操作在时间段内,即在T2点之前就已经执行完成了, T2点获取到的可能不是卡顿发生的准确时刻, 也就是说T2时刻获取到的信息,不能够完全反映卡顿的现场; 最后的T2点的堆栈信息只是表象,不能反映真正的问题 、处理,服务端有压力; 突破点:一个卡顿下多个堆栈大概率有重复; 解决:对一个卡顿下的堆栈进行hash排重, 找出重复的堆栈; 效果:极大地减少展示量,同时更高效地找到卡顿堆栈; ---- 参考:
卡顿原因 首先,我们需要明确一个定义,就是卡顿是什么? 死锁:主线程拿到锁A,需要获得锁B,而同时某个子线程拿了锁 B,需要锁A,这样相互等待就死锁了。 这里想到的就是将当前的线程栈进行捕捉,这样我们就可以找到当前卡顿在哪一行函数。 所以,这里监控卡顿的整体思路就是起一个子线程,去监控你所需要关注的线程(例如主线程)的活动情况,如果发现有卡顿,就将当前堆栈dump下来。 ? 上图可以看出,我们在这次监控卡顿的工具中主要监控的是线程RunLoop的超时情况,由于在iOS中线程的事件处理主要依靠的是RunLoop,如果单次RunLoop运行循环的事件超过某一时间,那就会产生出用户体验卡顿情况 ,例如内存堆栈的打印,卡顿次数的统计等等。