当前位置: 首页 > news >正文

青岛网站建设大全杭州软件开发

青岛网站建设大全,杭州软件开发,网站建设年终总结,咖啡网页设计素材本文将结合典型实战案例#xff0c;分析常见的造成卡顿等性能问题的原因。从系统工程师的总体角度来看 #xff0c;造成卡顿等性能问题的原因总体上大致分为三个大类#xff1a;一类是流程执行异常#xff1b;二是系统负载异常#xff1b;三是编译问题引起。 1 流程执行异…本文将结合典型实战案例分析常见的造成卡顿等性能问题的原因。从系统工程师的总体角度来看 造成卡顿等性能问题的原因总体上大致分为三个大类一类是流程执行异常二是系统负载异常三是编译问题引起。 1 流程执行异常 在这篇文章Android卡顿掉帧问题分析之原理篇-CSDN博客我们以滑动场景为例完整的分析了Android应用上帧显示的全流程默认开启硬件绘制加速条件下。下面我们用一张图来看看这个流程上可能引起卡顿、反应延迟等性能问题的点。 从上图可以看出在Android应用上帧显示的各个流程上都可能出现问题导致出现卡顿、反应延迟等性能问题。下面我们分类来分析一下各个流程上可能的引起卡顿等性能问题的点。 1.1 system_server引起应用卡顿 一、理论分析  框架system_server进程内部的各个核心服务AMS、WMS、PKMS等都有各自的对象锁和工作线程各个服务运行时相互之间存在交互可能出现某个线程持锁执行耗时操作而其它线程陷入长时间锁等待的情况。某些情况下当系统框架负载过重或流程出现异常情况下其工作线程之间相互等锁的现象会非常严重。如果此时应用App的UI线程中有Binder请求而系统框架内部处理请求的实现又恰好需要持锁就可能间接导致应用App的UI线程阻塞在Binder请求而引起App应用的卡顿问题。 二、典型案例分析 问题描述设备刚开机时桌面左右滑动出现卡顿。 问题分析结合Systrace工具分析问题原因如下 从以上问题Systrace的分析可以看出出现桌面滑动卡顿的原因是 桌面应用的UI线程tid:4927中通过Binder请求访问框架PKMS服务的getActivityInfo接口查询Activity的相关信息时出现长时间阻塞 而框架PKMS服务中处理此Binder请求的线程tid:5271逻辑需要持锁执行而当前此锁对象的“锁池”中至少已经有7个线程都已经在等待这把锁所以此线程进入锁对象的“锁池”中阻塞等待锁释 而此时持有该锁的线程为框架的android.bg工作线程tid:2608此线程中正持锁执行IO写磁盘等耗时操作且线程的优先级较低在刚开机阶段系统整体负载比较重的场景下抢不到CPU执行时间片而长时间处于Runnable状态导致运行时间较长 三、优化思路 针对此类system_server内部的各种锁等待或流程异常导致的性能问题。Google在历年的Android版本上也在不断针对优化通过优化流程尽量的减少流程中不必要的持锁或减小持锁范围。例如在Android P上推出的LockFreeAnimation无锁窗口动画就实现了无需持有WMS锁播放窗口动画从而极大减少窗口动画卡顿的概率Android 12上在 PackageManager 中引入只读快照减少了 92% 的锁争用。另外各大手机厂商也会在自家的ROM系统上针对这种情况对框架作出持续的优化通过分析持锁等待的关系找到问题源头的当前持锁线程利用一些空间换时间的缓存方案或优化CPU、IO等资源的调度与分配减少线程的持锁的时长从而改善其它线程锁等待的时长。 1.2 Input事件处理引起卡顿 一、理论分析 从前面Android卡顿掉帧问题分析之原理篇文章中的分析我们知道屏幕驱动上报的Input事件要经过框架的InputReader和InputDispatcher线程的读取与分发然后通过Socket发送到应用进程中再经过界面View控件树的层层分发后消费处理。这个过程中任意一个流程出现阻塞就能造成用户的触控操作得不到及时的响应出现用户感知的系统反应延迟或卡顿现象。 二、典型案例分析 问题描述微博应用界面手势滑动退出时界面卡住几秒钟才有反应。 问题分析结合Systrace工具分析问题原因如下 从以上问题Systrace的分析可以看出退出应用界面时出现卡住几秒的原因 首先看Systrace上system_server进程中标识Input事件分发的iq和“oq”队列的信息可以看到框架InputDispatcher对事件的分发处理没有出现阻塞或漏报等异常情况从微博应用对应的“wq”队列可以看到应用进程一直有没有完成处理消费的Input事件说明问题在微博应用进程侧看Systrace上微博应用侧的信息可以看到应用UI线程很长一段的deliverInputEvent的tag大概持续2.5秒左右且“aqime”队列中显示有持续很长一段时间的事件处理逻辑。说明应该是在应用进程UI线程中判断Input事件类型为返回键的Key事件所以先交给输入法应用进行处理但是输入法进程一直没有完成处理导致应用UI线程一直处于等待状态无法及时处理此Input事件说明问题出现在输入法应用侧然后我们用ps命令查看当前输入法进程信息发现输入法进程pid5897当前的状态为“D”说明处于进程“冻结”的休眠状态结合Systrace上显示的输入法进程的主线程信息显示发现其确实是一直处于Sleeping状态。所以此问题出现的原因就是因为输入法进程被异常“冻结”导致的。和负责维护进程“冻结”功能的同事沟通并分析日志后发现问题的原因是用户安装并设置了新的输入法应用进程“冻结”模块没有成功识别将其认定为普通后台进程所以进行了“冻结”从而导致了异常。 到此还剩一个疑问就是为什么输入法进程都被“冻结”而休眠了应用UI线程在等待2.5秒后还是能继续往下处理Input事件并成功退出应用Activity界面呢原因就是应用UI线程进入等待输入法处理Input事件时会设置一个超时这个时长就是2.5秒如果超时后输入法进程还是没有处理完就会强行结束等待的逻辑由应用UI线程继续往下处理Input事件。相关源码如下所示 /*frameworks/base/core/java/android/view/inputmethod/InputMethodManager.java*/ ... /** * Timeout in milliseconds for delivering a key to an IME. */ static final long INPUT_METHOD_NOT_RESPONDING_TIMEOUT 2500; ... // Must be called on the main looper int sendInputEventOnMainLooperLocked(PendingEvent p) {if (mCurChannel ! null) {...if (mCurSender.sendInputEvent(seq, event)) {...Message msg mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p);msg.setAsynchronous(true);mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);//1.处理Input事件时设置一个2500ms的超时检查return DISPATCH_IN_PROGRESS;}...}return DISPATCH_NOT_HANDLED; } ... case MSG_TIMEOUT_INPUT_EVENT: {finishedInputEvent(msg.arg1, false, true);// 2.时间到之后如果输入法还是没有完成Input事件处理则强行结束输入法对事件的处理逻辑return; } ... 三、优化思路 对用户触控事件的响应速度直接关系到用户对交互设备性能体验的感知所以一直以来都是系统性能优化工作的重中之重。多年来谷歌包括SOC厂商都有针对系统Input事件的处理流程作出优化以提升触控响应速度。例如高通基线上在2018年左右就有一笔提交优化应用进程侧的Input事件处理流程大概思路就是识别应用UI线程中收到第一个ACTION_DOWN的Touch事件后调用sendMessageAtFrontOfQueue接口在应用UI线程的消息队列的最前面插入一帧doFrame绘制任务这样界面不用等待下一个Vsync的信号的到来就能直接上帧显示从而减少整个Input触控事件的响应延迟。从Systrace上表现如下图所示 国内各大手机厂商也有各自的优化方案。比如硬件上采用触控采样率更高的屏幕屏幕触控采样率达到240HZ甚至480HZ。再比如监控到触控事件后提升CPU主频提升触控事件处理相关线程和渲染线程的优先级等方式从而优化事件触控响应速度。而对于应用APP开发者来说需要做的就是避免在Input触控事件的分发处理流程中执行耗时操作以免引起触控延迟或卡顿等性能问题。 1.3 应用UI线程耗时引起卡顿 一、理论分析 这部分逻辑主要由应用APP开发者控制。根据前文Android卡顿掉帧问题分析之原理篇中的分析可知UI线程耗时过长必然会导致Vsync周期内应用上帧出现超时。特别是屏幕高刷时代的到来留给应用UI线程处理上帧任务的时长越来越短。例如120HZ的高刷屏幕配上一个Vsync信号周期已经缩短到8ms左右。这要求应用APP开发者能写出更加高性能质量的代码。应用UI线程耗时引起的卡顿往往涉及的因素比较多下面列举一些常见原因 UI线程消息队列中存在除doFrame绘制任务外的其它耗时任务导致Vsync信号到来后无法及时触发UI线程执行doFrame绘制上帧任务而导致掉帧。例如界面布局XML文件的inflate解析如果界面布局文件比较复杂就会有大量的IO与反射等耗时操作。又或者UI线程中有decodeBitmap解析大图片的耗时操作。UI帧的doFrame绘制任务处理耗时过长导致掉帧。最常见的问题就是应用界面布局存在过度绘制导致measure/layout/draw任务的计算复杂度成倍上升。再比如应用界面布局中的部分View控件层面如果关闭了硬件绘制加速就会触发View#buildDrawingCache的耗时操作从而导致整个draw动作耗时过长而引起掉帧。UI线程存在大量的阻塞等待导致上帧超时。UI线程陷入阻塞等待常见的原因就是跨进程的Binder调用阻塞和进程内的同步锁竞争等待。还有一类情况就是频繁的GC内存回收引起(一般为进程内存抖动或内存泄露引起)。 二、典型案例分析 问题描述三方应用书旗小说界面上下滑动严重掉帧卡顿。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到应用UI线程上帧的doFrame流程中主要耗时点在buildDrawingCache的流程上。下面我们结合源码来看看什么情况下draw流程中会出现buildDrawingCache的动作 /*frameworks/base/core/java/android/view/View.java*/ ... public RenderNode updateDisplayListIfDirty() {...if (layerType LAYER_TYPE_SOFTWARE) { //判断View的layerType为LAYER_TYPE_SOFTWARE也就是关闭了硬件绘制加速执行buildDrawingCachebuildDrawingCache(true);...}else{...draw(canvas); //走硬件绘制加速的流程...}.... } ... 从代码可以看出当判断某个View空间的layerType为LAYER_TYPE_SOFTWARE也就是关闭了硬件绘制加速的情况下就会触发走到buildDrawingCache的耗时逻辑中。所以此问题就是由于书旗小说应用的界面布局中一个名为OriWebViewEx 的View控件关闭了硬件绘制加速导致。 问题描述Twitter应用界面上下滑动严重掉帧卡顿。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到三方应用Twitter出现掉帧的主要原因是其UI线程中存在大量耗时的inflate解析xml布局文件的操作且出现问题时UI线程已经持续Running到CPU 5大核心上但是还是出现严重的上帧超时。 三、优化思路 针对应用UI线程耗时引起卡顿的问题原则就是尽量减轻UI线程的负担。针对不同的引起问题原因常见的优化思路大致如下 异步处理各种耗时操作尽量放到子线程异步处理。比如使用View的异步线程inflate方案decodeBitmap加载图片的耗时操作移到子线程统一处理等。 逻辑优化必须要在主线程执行的逻辑应尽量优化减少计算频次避免重复计算。比如采用约束布局解决嵌套过多的问题避免过度绘制优化应用的内存占用避免内存泄露、内存抖动等问题从而减少GC触发的次数优化内部代码逻辑尽量减少主线程陷入同步锁竞争等待的状态原则上不要主动去关闭硬件绘制加速。 流程复用能复用的逻辑尽量复用以避免多次调用产生的性能开销。比如ListView的Adapter中实现View的复用减少View的inflate执行次数。另外UI线程中Binder请求框架查询一些系统信息能够一次查完就不要分多次执行。且查询结果应尽量缓存在内存中实现复用避免多次反复的查询造成主线程频繁陷入Binder阻塞等待。 1.4 SurfaceFlinger耗时引起卡顿 一、理论分析 前文的分析可以知道SurfaceFlinger在Android系统的整个图形显示系统中是起到一个承上、启下的作用负责收集不同应用进程Surface的绘制缓存数据进行的合成然后发送到显示设备。所以如果SurfaceFlinger的处理流程上出现耗时或阻塞必然会导致整个应用的上帧显示的流程出现超时而掉帧。特别是随着屏幕高刷时代的到来Vsync周期不断缩短留给SurfaceFlinger处理的时间也越来越短对SurfaceFlinger的性能提出了更高的要求。这也是谷歌、SOC厂商包括各大手机厂商做系统性能优化的重点。 二、典型案例分析 问题描述设置120HZ高刷模式下手机录屏、投屏场景下出现帧率下降。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到开启录屏或投屏后部分Layer需要采用效率更低的GPU合成方式主要是因为高通平台HWC不支持回写SurfaceFlinger的主线程中需要实现drawLayers的动作还需要将图层数据写入到MediaCodec缓存中总体负载较高导致在8ms120HZ高刷模式下内无法完成一帧数据的处理而出现帧率下降的问题。 三、优化思路 针对SurfaceFlinger引起的性能卡顿问题常见的优化思路有 谷歌通过cpuset的配置默认场景下SurfaceFlinger只能使用4个CPU小核心运行部分厂商会在投屏或录屏等负载比较重的场景下放开这个限制让SurfaceFlinger进程能跑到CPU大核心上。部分厂商在开启录屏的情况下会锁定屏幕刷新率最高不超过60HZ以减轻SurfaceFlinger进程的压力。Android 12上谷歌就将各个应用对应的BufferQueue的管理工作移动到应用进程侧处理以减轻SurfaceFlinger进程的负载。 2 系统负载异常 CPU、GPU、内存、磁盘等都是系统内各个进程任务的运行所必需的公共系统资源。这就涉及到一个复杂的资源调度与分配的问题实现将系统资源与各个不同进程的需求进行合理的匹配以保证进程任务能够流畅的运行。这就涉及到两个问题 这些系统公共资源是否充足。比如当进程需要时当前CPU核心的运行主频算力是否足够高系统剩余内存是否足够大磁盘的读写速度是否足够快。这些系统资源的分配是否合理。比如当前优先级更高的前台应用进程相对于后台进程是否能获得更多的CPU调度运行时间片和I/O带宽等资源以保证界面的流畅运行。 从软件的角度出发每个应用任务进程都希望自己获得无限的CPU算力、无限的内存资源分配等能力以保证其能够流畅的运行。但是从硬件的角度出发各种系统的公共资源配置都是有限的不可能无限的提供给每个任务进程且在移动设备上还要考量功耗与发热的问题需要限制各种系统资源的供给。所以如何协调这种供需关系之间的矛盾将宝贵的系统资源合理的分配给当前最需要的任务进程以最小的资源开销保证系统的流畅运行就是考验操作系统的设计者和性能优化工程师的功力的问题弄不好就可能出现应用任务进程的运行受限于系统运行资源的分配而出现各种性能问题。 2.1 CPU调度引起卡顿 一、理论分析 CPU算力资源绝对是系统内最重要的公共资源之一每个应用程序的正常运行都需要CPU的调度执行。目前的主流移动设备搭载的CPU基本上都是采用多核心架构设计按照算力的大小设置有多颗CPU运算核心以高通的骁龙8 gen 1处理器为例其拥有8颗CPU运算核心包含四个小核、三个中核和一个大核算力依次递增功耗也逐渐增大。 且Linux操作系统内核中会有相应的scheduler和governor调度器来管理每颗CPU核心上当前运行的任务的排程以及每颗CPU核心当前运行的主频每颗CPU核心都有一个运行主频参数可以支持在一定的范围内动态调节主频越高算力越强相应的功耗也就越大、节能状态等参数以达到最佳的性能与功耗的平衡。但是很多时候由于CPU运行核心上的任务排布不合理或运行主频过低导致的算力过低无法满足应用进程的需求就可能导致应用出现卡顿掉帧等性能问题。常见的一些原因如下 后台应用进程任务持续运行抢占CPU运行资源或者处于功耗管控直接关核导致前台应用的UI线程任务无法及时的获得CPU运行算力执行长时间处于Runnable状态而出现上帧超时掉帧问题某些时候出于功耗与发热的考量将CPU的运行主频压的过低导致算力不足。应用的上帧线程上的任务需要Running很长一段时间而出现上帧超时掉帧。 二、典型案例分析 问题描述腾讯视频应用中观看视频时播放弹幕卡顿。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到腾讯视频播放视频时出现掉帧卡顿的原因是因为其负责弹幕上帧的线程无法获得CPU运行资源而长时间处于Runnable状态导致上帧出现严重超时。  进一步分析原因发现存在两个问题一个就是看CPU Trace信息发现此时只有CPU 0-3四个小核心和一个CPU 4一个中核心在运行而算力更强的CPU 5-7都处于关闭状态导致系统总体算力受限另一个问题就是前台应用腾讯视频进程内的所有线程运行任务都只分配到CPU 4上运行其它几个小核心处于空闲状态也没有使用导致腾讯视频应用的运行严重受限。 最终经过分析找到问题的根本原因就是一、关闭算力更强的CPU 5-7的原因是系统组为了降低用户全屏看视频场景下的功耗而故意为之二、腾讯视频只能运行在CPU 4上的原因是因为该项目使用的是高通最新的SM8450平台该平台采用ARM V9架构设计32位的应用只能使用CPU4-6三个中核运行而应用商店提供的腾讯视频刚好就是32位的版本。 至此问题水落石出后面解决问题思路就是一方面推动应用商店上架腾讯视频64位版本二是系统组那边需要针对32位的应用前台全屏看视频的场景下的CPU配置做出调整不再全部关闭CPU 5-7三个算力较强的核心。 问题描述桌面界面左右滑动出现卡顿掉帧。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到前台应用桌面出现掉帧的原因是其UI线程抢不到CPU运算资源而长时间处于Runnable状态。而此时CPU上分布有大量后台应用的任务持续运行。出现这个问题的原因是国内部分应用存在很多进程保活机制会在后台持续运行并想方设法提升其进程的优先级。所以在系统关闭了相关针对性的管控后就会出现问题。 三、优化思路 针对CPU调度问题引起的性能卡顿问题常见的优化思路有 1. 基于cgroup的进程资源隔离。Android系统上继承了linux的cgroup机制以控制进程的资源占用让重要的进程获得更多的系统资源。涉及的系统资源如下图所示 其中cpuset可以实现限制进程只能运行在指定的CPU核心上、cpuctl可以实现控制前后台进程的CPU用量和freezer可以实现控制进程处于冻结休眠状态完全放弃CPU执行权就是对进程CPU资源的控制。后面的top-app标识当前进程所属的资源分组。cgroup机制中会将不同的运行进程分成不同的资源组比如前台应用属于top-app组后台应用属于background组。不同的组可以支持配置不同的资源使用权限比如通过cpuset的配置background组中的进程被限制只能运行在cpu 0-3三个小核心上而处于top-app组中的进程可以使用所有的cpu核心资源。以cpuset为例如下图所示 通过这种限制后台不重要的进程的CPU资源占用从而让前台重要的应用进程获得更多的CPU资源至于进程的前后台优先级定义主要是由框架AMS服务来管理维护通过写进程的oom_score_adj值来标识。国内各大手机厂商的系统性能优化的策略中有很大一部分工作都是依赖于cgroup机制来实现的通过对系统资源精细的定义划分和应用进程优先级与功能场景的精准识别来实现对资源的合理分配达到性能与功耗的最佳平衡。 2. 基于场景识别的CPU调度策略配置。主要工作包括 对CPU基础配置影响各核的性能输出包括CPU Frequency运行主频调节、排程器大核小核工作分配策略upmigrate/downmigrate/sched_boost的调节根据CPU各核心的任务负载对线程任务进行大小核分布的迁移调整以上都是通过Soc厂商提供的Perf服务接口设置参数去写相关的设备节点实现以高通平台为例相关节点如下图所示 还有温控策略的配置调整出于功耗与发热的考量移动设备上温控机制thermal-engine服务会根据遍布设备内部的各个温度传感器读取的温度值按照一定的温度阈值对CPU运行主频进行限制以防止设备过热 对场景的定义识别与策略配置比如定义应用冷启动场景在框架进行识别并动态将CPU主频进行拉升一段时间以提升应用打开速度定义视频播放的场景在框架进行识别然后对CPU主频进行限频在保证播放流畅的前提下尽量降低功耗和发热这块也属于国内各大手机厂商的系统性能优化的核心工作。如何实现精确的场景定义与识别精准控制CPU的性能输出用最小的功耗保证应用界面的流畅运行就是对厂商功力的考验。 3. 对三方应用后台相互唤醒和进程保活机制的限制防止其在后台持续运行抢占CPU算力资源。这块也是国内各大手机厂商系统优化的重点工作之一。 2.2 GPU调度引起卡顿 一、理论分析 GPU算力资源是继CPU算力外系统内另一个重要的公共资源从前文Android应用上帧显示的流程分析可知应用对每一帧画面的渲染处理都离不开GPU算力的支撑。和CPU类似设备的GPU也有自己的运行主频运行主频越高算力越强同时发热也就越大且支持在一定的范围内调节以实现功耗和性能的最佳平衡。以高通SM8450平台所搭载的型号为Adreno 730的GPU为例其参数信息如下图所示 从上图可以看到GPU支持在一定的范围内动态调节运行主频Soc厂商和国内的手机厂商会根据任务负载和使用场景动态调节GPU的工作频率以实现功耗与性能的最佳平衡。但是如果调节不合理就可能引起性能问题常见的一些原因如下 部分大型游戏应用如原神需要大量的GPU算力进行游戏画面的实时渲染处理如果系统的GPU运行主频算力没有及时的跟上来无法满足应用对GPU算力的需求就会导致游戏应用上帧时出现阻塞超时而掉帧部分应用在后台利用GPU做一些图像处理的并行计算抢占了系统的GPU算力资源就可能导致前台应用绘制上帧时由于GPU算力不足使其渲染线程陷入长时间阻塞等待GPU渲染完成的Fence信号的状态最终出现上帧超时卡顿的问题。 二、典型案例分析 问题描述三方应用UC浏览器界面滑动卡顿。 问题分析结合Systrace工具分析问题原因如下 从上图的Systrace可以看出UC浏览器出现上帧超时的主要原因是其RenderThread渲染线程长时间阻塞在queueBuffer上帧的流程上而queueBuffer阻塞在SurfaceFlinger进程那边的Binder响应而SurfaceFlinger进程中又需要等待GPU那边完成画面渲染处理的fence信号的从应用进程侧的waiting for GPU completion的systrace tag也能看出。如下简化代码所示 /*frameworks/native/libs/gui/BufferQueueProducer.cpp*/ status_t BufferQueueProducer::queueBuffer(int slot,const QueueBufferInput input, QueueBufferOutput *output) {ATRACE_CALL();...// Wait without lock heldif (connectedApi NATIVE_WINDOW_API_EGL) {// Waiting here allows for two full buffers to be queued but not a// third. In the event that frames take varying time, this makes a// small trade-off in favor of latency rather than throughput.lastQueuedFence-waitForever(Throttling EGL Production); // 等待GPU fence信号}return NO_ERROR; } 也就是说问题出在系统的GPU算力资源比较紧张。后来分析应用掉帧的同一时间段系统的其它运行进程的systrace表现发现系统的图库应用正在执行一些Bitmap图像处理的动作。再结合日志分析后与负责图库的同事沟通最终找到问题的根本原因所在图库应用中有一个事物分类相册的功能当时正在后台使用GPU进行照片图像的特征识别与处理的逻辑抢占了系统GPU算力资源从而导致前台UC浏览器应用的渲染线程阻塞在等待GPU的fence信号的流程而出现掉帧。 三、优化思路 针对GPU调度问题引起的性能卡顿问题常见的优化思路有 基于场景的GPU调度策略配置。这块主要是结合前台应用场景的需求动态调节GPU的运行主频等参数以最小的功耗满足应用的性能需求。这块考验各大手机厂商的调教水平也是厂商进行游戏优化调教的重点工作之一。后台应用进程抢占GPU算力资源的管控。主要是限制后台应用的运行防止其出现抢占GPU算力资源的行为以保证前台应用的流畅运行。 2.3 低内存引起卡顿 一、理论分析 内存也绝对算的上是一个重要的系统公共资源系统内任何进程的正常运行都需要消耗一定的内存资源。一般来讲设备的RAM硬件物理内存的大小是固定且有限的4G、8G或12G等而系统内运行的所有进程都需要共享这些有限内存资源。如何用有限的内存资源去满足系统各个应用进程无限的需求这就涉及到一个系统内存管理的逻辑。这是一个复杂的问题几乎贯穿了整个Android系统的各个层级。从Linux内核到Art虚拟机再到Framework框架甚至到APP应用都会有各自的内存管理的策略。关于Android系统的内存管理的详细逻辑由于篇幅所限本文就不详细展开。我们以systemui应用进程为例来看看一个普通应用进程的内存占用分布 合理的内存的分配与管理无论对系统和应用来讲都至关重要。因为内存问题既能引发稳定性问题也能引发卡顿性能问题。下面我们分别来分析一下 1. 内存引起的稳定性问题 因为系统总的内存资源是有限的为了防止单个应用进程无限制的占用内存资源Android系统设计了很多机制来遏制这种情况的产生。比如在虚拟机层面谷歌设计对每个应用进程占用的Dalvik Heap的内存大小做出了限制超过一定的阈值记录在dalvik.vm.heapgrowthlimit的property中一般为256M就会触发OutOfMemeory的异常导致应用进程崩溃。此外Android系统还引入了lmkd低内存守护机制当系统总的可用内存低于一定的阈值就会按照进程优先级将占用内存比较大的应用进程杀掉。32位的应用虚拟内存的寻址空间最大为4G当应用进程的虚拟内存占用超过4G时就无法继续为其分配内存产生OOM类型的报错出现应用崩溃或黑屏等问题。另外Android系统基于Linux内核也绩承了Linux系统对应用进程的相关限制。如果应用进程中开启的线程过多每创建一个空线程也会有一定的内存开销超过/proc/sys/kernel/threads-max中定义的上限也会报出OOM异常导致应用进程崩溃再比如应用进程中打开的文件句柄过多超过/proc/pid/limits节点中的定义上限也会报出OOM异常导致应用进程崩溃。如下图所示 2. 内存引起的性能性问题 当应用出现内存抖动或内存泄露的问题时就会导致虚拟机的GC频繁工作甚至触发stop-the-world事件造成应用的UI线程出现挂起阻塞最终导致上帧出现超时而掉帧。 当后台活跃运行的应用进程过多时会造成系统总体的剩余内存偏低。此时主要有两个问题可能会造成应用的卡顿 a、当内存zone处于低水位时内核会频繁唤醒kswapd的线程起来执行内存回收的动作另外内核PSI内存压力信号也会频繁唤醒lmkd进程进行扫描和杀进程。这些动作都会占用CPU运行资源导致前台应用UI线程由于抢不到运行CPU资源而出现长时间处于Runnable的问题 b、当系统内存不足时kswapd的线程被唤醒进行内存回收会将page cache内存页中已经缓存的磁盘文件信息进行大量释放导致应用进程中的一些IO读文件操作比如 view 读文件读配置文件、读 odex 文件等由于page cache无法命中触发缺页中断陷入内核态阻塞等待一直等到readahead机制从磁盘中将文件内容全部读取出来才能释放返回。当大量进程在进行IO操作时又进一步加重底层IO的阻塞时长。最终导致前台应用的UI线程长时间处于Uninterruptible Sleep - Block I/O的状态而出现上帧超时卡顿问题。 二、典型案例分析 问题描述在三方应用唯品会的首页界面上下滑动严重掉帧卡顿。 问题分析结合Systrace工具分析问题原因如下 从Systrace上可以看到唯品会应用出现掉帧卡顿的主要原因如下  系统内存紧张频繁唤醒kswapd0线程进行内存回收操作其持续抢占CPU 5大核心运行导致应用的UI线程和RenderThread渲染线程频繁出现抢不到CPU资源得不到执行而处于Runnable的状态从而导致应用上帧超时而掉帧系统内存紧张时page cache磁盘文件缓存被内存回收导致应用的UI线程和RenderThread渲染线程中的一些IO读文件操作无法命中page cache缓存而频繁陷入内核Uninterruptible Sleep - Block I/O的状态导致应用上帧超时而掉帧。 三、优化思路 针对内存问题引起的性能卡顿问题常见的优化思路有 1. 在应用进程侧作为应用开发者 需要解决应用自身的内存泄漏问题避免频繁的内存分配回收出现的内存抖动现象 并尽量优化应用的内存占用包括优化图片加载占用、采用内存更高效的数据结构如ArrayMap、采用对象池和图片复用等内存复用机制、功能比较复杂的应用采用多进程方案、尽量优化应用APK包体积大小、监听onTrimMemory事件并及时释放内存中的不必要缓存等 尽量不要做一些应用进程保活的机制以免增加系统总体的内存负担 将应用升级适配到64位版本以免陷入虚拟内存耗尽而进程崩溃的局面。 使用Android Studio自带的Profile分析工具进行内存分析与优化具体用法可以参考这篇文章https://www.jianshu.com/p/72b213fa6a26。 2. 在系统总体层面这部分内容主要属于谷歌和手机厂商的工作常见的一些针对性优化手段有  调整lowmemorykiller的杀进程的门限值让其提前介入清理掉一些低优先级的进程而释放内存以免系统陷入低内存状态 适当提高 extra_free_kbytes 值让kswapd线程能提前介入进行内存回收以免系统陷入低内存状态 框架中设计后台应用查杀功能定期清理后台低优先级应用进程并限制三方应用的后台保活机制从而释放内存以免系统陷入低内存状态 通过cpuset配置限制kswapd不让其使用部分CPU大核从而让出CPU资源给前台应用的UI和渲染线程使用 配置和启动ZRAM和app compaction后台内存压缩机制从而减少应用进程后台的内存占用腾出更多的系统可用内存 优化系统的磁盘IO性能采用UFS3.1等性能更强的存储器以减轻系统出现内存低的情况时出现IO阻塞的时长。 2.4 磁盘I/O引起卡顿 一、理论分析 磁盘是现代计算机系统实现数据持久化存储的核心硬件模块。也是继CPU和内存外系统内另一个重要的公共资源。Android系统内应用程序的运行一般都会伴随有大量的磁盘I/O读写的操作比如读写数据库、加载XML布局文件、读取配置文件等。但是相对于CPU和内存相比磁盘的读写访问速度是比较慢的很容易成为CPU运行的瓶颈导致系统被拖累。当应用进程的线程中发生直接I/O磁盘读写时就会导致线程进入Uninterrupt Sleep-Block I/O阻塞状态如下图所示 在开始分析磁盘I/O读写的瓶颈引起性能问题原因之前我们先借用一张简化图来总体看看Linux系统的I/O栈 从上图可以看出整个Linux 下的 I/O栈大致有三个层次 文件系统层以 write 为例内核拷贝了 write 参数指定的用户态数据到文件系统 Cache 中并适时向下层同步。块层管理块设备的 I/O 队列对 I/O 请求进行合并、排序。设备层通过 DMA 与内存直接交互完成数据和具体存储设备之间的交互。 可能存在的性能瓶颈问题如下 为了优化文件读写的性能减少磁盘的I/O 操作Linux内核系统提供了页缓存Page Cache技术以页为单位将磁盘上的文件内容缓存在内存中从而提供了接近于内存读写速度的文件顺序读写速度也就是Buffered I/O。但是当系统剩余内存不足时系统会回收Page Cache页缓存内存导致文件读写操作直接落到磁盘上从而极大降低I/O性能。这也就前一小节中分析的低内存导致的性能卡顿问题。上层所有的I/O 请求都会放入队列中进行合并排队处理这样就可能引发不同应用进程之间的资源抢占问题。比如后台进程存在大量读写磁盘的操作请求占用系统的I/O 资源这就会导致前台应用的I/O 请求出现在队列中阻塞排队等待的现象最终导致掉帧卡顿问题。文件系统的性能瓶颈。比如针对NAND闪存特性设计的f2fs文件系统相比于ext4文件系统能够提升小文件的随机读写性能并能减少碎片化的问题。再比如Android 11上引入的Fuse文件系统增加I/O读写的开销导致sdcard路径下的部分路径文件的I/O读写性能下降。闪存的读写性能瓶颈。一个就是闪存硬件的读写性能差异比如UFS 3.0相对于UFS 2.1来讲顺序读取速度快90%顺序写入速度更是提升160%另外一个问题就是闪存重复写入需要先进行擦除操作这样随着时间的推移磁盘碎片变多剩余空间少一个内存页的写入会引起整个磁盘块的迁移造成耗时操作也就是早期Android手机给人形成“越用越卡”的印象的原因之一。 二、优化思路 针对I/O磁盘性能的瓶颈总体优化思路从两个角度来看 1. 从手机厂商角度 采用更大的内存硬件配置并从总体上优化系统的内存占用。以防止出现系统低内存状态下Page Cache页缓存被回收后应用直接写磁盘而导致的I/O阻塞卡顿问题 启用Linux的cgroup机制对I/O资源的进程隔离机制blkio将进程按照优先级进行分组分为前台进程、后台进程、甚至可以根据需求进行更详细的自定义划分以分配不同的I/O带宽资源从而解决后台应用进程抢占前台应用I/O资源造成的卡顿的问题 采用f2fs文件系统替换ext4文件系统以提升文件系统的性能可以针对部分系统文件管理类的应用不走默认的fuse路径而是走f2fs以提升其读写性能表现采用读写性能更强的闪存器件比如UFS 3.1启用fstrim磁盘碎片整理功能在息屏、充电等条件下触发磁盘碎片整理的动作从而减少磁盘碎片提升磁盘读写性能系统手机管家模块可以引导用户定期进行垃圾文件的清理以保证磁盘有充足的剩余空间 基于mmap内存映射机制将系统运行常访问的文件Lock锁定到内存缓存中以提升文件读写的性能减少真正发生I/O磁盘读写的概率减轻系统的I/O负载。Android系统框架中的PinnerService服务主要职责就是这个如下图所示   2. 从应用开发者角度  选择合适的文件读写操作。对读写速度有较高的要求并允许低概率的数据丢失问题就采用系统默认的基于Page Cache的缓存I/O对文件读写的速度要求不高但是需要严格的保证数据不会丢失就使用Direct I/O如果需要对同一块区域进行频繁读写的情况对读写性能要求极高可以采用mmap 内存映射机制实现读写文件比如腾讯开源的用于改善原生SharePreferences机制性能的存储工具MMKV就是这个原理实现的。I/O 方式的选择。一个是对于阻塞I/O操作尽量放入子线程执行以免阻塞UI线程二是适当采用异步I/O减少读取文件的耗时提升CPU整体利用率比如Okio就支持异步I/O操作。优化数据结构建立内存缓存尽量减少不必要的I/O 3 编译引起卡顿性能问题 编译引起的性能问题主要分为两类一类是代码的解释执行耗时运行时VerifyClass执行耗时等引发卡顿二类是编译本身引起的卡顿问题比如dex2oat编译抢占CPU算力资源进程中的Jit编译线程抢占CPU算力资源。 3.1 代码解释执行耗时 一、理论分析 Art虚拟机有两种代码执行模式quick code 模式和 Interpreter 模式。对于dex字节码文件采用的是Interpreter解释执行的模式每次执行代码虚拟机需要将代码转换成机器指令集然后交给CPU去执行所以执行效率比较低早期Android系统被诟病性能差的原因之一。而对于经过编译AOT的dex2oat编译或JIT运行时及时编译都需要消耗一定的磁盘空间存储编译出来的机器码文件后生成的ELF格式机器码文件如.oat格式文件、.art格式文件采用quick code模式直接执行arm 汇编指令执行效率较高。为了做到性能、磁盘空间占用以及应用安装速度之间的最佳平衡从Android 7.0 开始采用AOTJIT解释执行的混合模式其特点如下 应用在安装的时候dex中大部分函数代码不会被编译。App运行时dex文件先通过解析器被直接执行热点函数会被识别并被JIT编译后存储在 jit code cache 中并生成profile文件以记录热点函数的信息。手机进入 IDLE空闲 或者 Charging充电 状态的时候系统会扫描 App 目录下的 profile 文件并执行 AOT 过程进行编译。 所以ART虚拟机在执行一个函数过程中会在 Interpreter 解释器模式和quick code模式切换具体切换规则如下图所示 从上图可以看出有些时候应用部分代码还是按照Interpreter 模式执行运行效率较低从而产生一些性能问题。  二、典型案例分析 问题描述淘宝等三方应用冷启动速度慢于同平台竞品机型。 问题分析结合Systrace工具分析问题原因如下 从与竞品机器的对比Systrace分析可以看到同一个应用且在两台手机CPU型号和运行主频一致的情况下竞品机器上应用冷启动期间UI线程的Running时长更短且Jit工作线程上的热点代码编译任务明显少很多。从而可以推断出问题原因在于竞品机器上的应用代码大部分是以机器码直接执行而我们是以字节码解释执行所以效率更低运行时间更长。为什么会出现这个差异呢后来对比日志分析发现原因是竞品机上应用第一次安装打开后一段时间后系统会触发一次speed-profile模式的dex2oat编译会根据应用运行期间JIT搜集到的热点函数信息保存后生成的Profile描述文件进行编译从而将应用启动期间的大部分代码函数编译成了机器码.oat文件后续再启动应用时即可直接以quick code 模式执行机器码所以执行效率更高。 三、优化思路 针对代码解释执行造成的性能问题大致优化思路是尽量让应用代码以机器码形式运行部分有效的手段有 部分手机厂商在手机预置的应用商店中下载的三方应用除了APK文件外还会包含保存有应用热点函数信息的Profile描述文件这样在应用dex2oat安装时选择speed-profile模式就会根据Profile描述文件将应用的大部分热点函数直接编译成机器码从而极大的提升应用的性能表现。在手机息屏充电进入Idle状态后通过JobScheduler机制启动后台服务扫描 App 目录下的 profile 文件并执行 AOT 过程进行编译以达到手机越用越快的效果。 3.2 编译本身耗时 一、理论分析 在dex2oat进程编译应用的过程中系统会启动很多线程消耗大量的CPU算力资源。可能会导致前台应用由于抢不到CPU算力资源其UI线程长时间处于Runnable状态而卡顿。另外应用进程内部Jit工作线程动态编译时持续运行如果负载较重持续跑到CPU大核上也会造成CPU算力资源抢占。 二、典型案例分析 问题描述抖音应用界面严重卡顿。 问题分析结合Systrace工具分析问题原因如下 从上图可以看出抖音应用界面卡顿的原因是因为其UI线程抢不到CPU算力资源而长时间处于Runnbale状态而导致这个问题的很大一部分原因就是此时后台dex2oat进程创建多个线程持续执行应用编译动作抢占CPU算力资源。 三、优化思路 针对编译本身耗时引起的性能问题部分有效的手段有 通过cpuset配置限制dex2oat进程和Jit工作线程对CPU的使用使其不抢占CPU大核心算力资源并设置参数限制其创建的线程数。dex2oat编译应用的动作尽量放在设备息屏设备处于Idle状态下进行以免影响前台用户的操作限制三方应用在后台触发执行dex2oat编译动作从Android 10 开始谷歌官方通过Selinux权限的管控禁止了三方应用触发dex2oat的权限
http://www.zqtcl.cn/news/327502/

相关文章:

  • seo网站优化推广怎么做龙岗中心医院
  • 建网站程序智能网站建设平台
  • 建筑公司分几级资质seo入门培训
  • wap类网站上海网站建设免费推
  • 网站建设哪家好公司建设银行网站怎么登陆不
  • 关于建设网站的需求wordpress不能发布文章
  • 如何一键建淘宝客网站中国建设银行金华分行网站
  • 给wordpress添加公告英语seo
  • 佛山市网站建设系统wap浏览器网页版
  • 关于小说网站的一些建设流程学做蛋糕有哪些网站
  • 益阳购物网站开发设计禹城网站制作
  • 教育网站开发文档全网营销推广案例
  • 最流行的网站开发框架wordpress阅读权限
  • 怎么做推广网站创立网站
  • 制作自己的网站需要什么材料网站计费系统怎么做
  • 网站和域名的区别昆山网站开发建设公司
  • 兼职网站推广如何做西安市商标局
  • 打开网站说建设中是什么问题莱芜金点子招小时工
  • 做网站的相关协议秦皇岛解封最新消息今天
  • 网站托管维护方案新闻媒体发稿平台
  • 网站扩展名四平网站建设怎么选
  • 网站制作价格与售后视频网站建设有什么意义
  • 网站建设+太原1核1g可以做几个网站
  • 电商设计网站有哪些内容西安百度推广外包
  • 深圳网站建设价格多少做废旧金属的网站
  • wordpress 文档超级优化空间
  • 湖北seo网站推广官方网站怎么制作
  • 随州网站seo诊断wordpress 只显示一个主题
  • 建站登录可信网站认证 费用
  • 互站网站源码用jsp做网站一般会用到什么