Android 系统性能优化问题及显示原理

2022-05-08 07:34:24包邦春
导读 大家好,我是本期栏目编辑小友,现在为大家讲解Android 系统性能优化问题及显示原理问题。 说到安卓手机,大多数人的印象都是一段时间后变

大家好,我是本期栏目编辑小友,现在为大家讲解Android 系统性能优化问题及显示原理问题。

说到安卓手机,大多数人的印象都是一段时间后变得有点卡壳,有些程序在运行过程中莫名其妙的死机。打开系统文件夹,发现文件多了很多,再用手机管家APP不断清理优化,才感觉运行速度提升了一点。即使手机在各种性能运行软件上得分遥遥领先,还是觉得无论内存空间有多大,都远远不够。相信每一个使用安卓系统的用户都有过以上类似的体验。的确,安卓系统在流畅度上不如IOS系统。为什么呢?看手机的硬件配置,安卓设备不会输给iOS设备,甚至比IOS设备更好。关键在于软件。

造成这种现象的原因有很多,列举如下:

其实近年来随着安卓版本的迭代,谷歌提供的安卓系统也越来越流畅,目前发布的最新版本是安卓8.0奥利奥。但国内大多数用户使用的安卓手机都是各大厂商定制的版本,往往不是最新的原生系统内核。大部分可能还停留在安卓5.0系统上,甚至安卓6.0以上的比例还太小,更新有延迟。

由于安卓系统的源代码是开放的,只要遵守相应的协议,每个人都可以修改源代码,所以国内厂商会将基于安卓的源代码转化为自己对外发布的系统,如小米手机Miui系统、华为手机EMUI系统、Oppo手机ColorOS系统等。既然各家厂商都修改了安卓原生系统的源代码,那么就会出现一个问题,那就是著名的安卓碎片化问题,其本质就是不同安卓系统的应用兼容性不同,无法做到一致性。

由于各种安卓碎片化和兼容性问题,安卓开发者在开发应用时需要适应不同的系统。同时,每个安卓开发者的开发水平参差不齐,编写的应用程序性能也存在不同类型的问题,导致用户在使用过程中体验不一。那么一些问题就会变成安卓系统的问题,影响安卓手机的评价。

性能优化

今天我想重点讲讲安卓APP性能优化,也就是开发应用应该注意什么,如何更好的提升用户体验。一个好的应用程序不仅要有吸引人的功能和交互,还要有很高的性能要求。即时应用很有特色,在产品前期可能会吸引一些用户。但是如果用户体验不好,也会给产品带来不好的口碑。

那么一个好的应用应该如何定义呢?主要有以下三个方面:

服务/功能

逻辑互动。

出色的表现。

众所周知,安卓系统作为基于移动设备的操作系统,在硬件配置上有一定的局限性。虽然配置越来越先进,但还是比不上PC。如果CPU和内存使用不合理或者长时间消耗资源,就会遇到内存不足导致的稳定性问题,CPU消耗过多导致的卡顿问题等等。

遇到问题时,大家都想着联系用户,查看日志,却不知道关于性能问题的反馈,原因非常难找。原木大多用处不大。为什么呢?因为大多数性能问题是不可避免的,很难重现问题位置,也没有关键日志,所以不可能找到原因。这些问题极大地影响了用户体验和功能使用,所以了解一些性能优化的解决方案,优化我们在实际项目中的应用,从而提高用户体验是非常重要的。

四个方面

用户体验的性能问题可以归纳为四类:

流利的

稳定的

节省电力和流量。

安装包很小

性能问题的主要原因有哪些,有相同也有不同,但归根结底无非是内存使用、代码效率、合适的策略逻辑、代码质量和安装包大小,分类如下:

从图中可以看出,构建一个高质量的应用程序应该针对四个方向:快速、稳定、经济和小。

快速:使用时避免堵塞,响应速度快,减少用户等待时间,满足用户期望。

稳定:

减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。

省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。

小:安装包小可以降低用户的安装成本。

要想达到这4个目标,具体实现是在右边框里的问题:卡顿、内存使用不合理、代码质量差、代码逻辑乱、安装包过大,这些问题也是在开发过程中碰到最多的问题,在实现业务需求同时,也需要考虑到这点,多花时间去思考,如何避免功能完成后再来做优化,不然的话等功能实现后带来的维护成本会增加。

卡顿优化

Android 应用启动慢,使用时经常卡顿,是非常影响用户体验的,应该尽量避免出现。卡顿的场景有很多,按场景可以分为4类:UI 绘制、应用启动、页面跳转、事件响应,如图:

这4种卡顿场景的根本原因可以分为两大类:

• 界面绘制。 主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。

• 数据处理。 导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况: 一是数据在处理 UI 线程, 二是数据处理占用 CPU 高,导致主线程拿不到时间片, 三是内存增加导致 GC 频繁,从而引起卡顿。 引起卡顿的原因很多,但不管怎么样的原因和场景,最终都是通过设备屏幕上显示来达到用户,归根到底就是显示有问题,所以,要解决卡顿,就要先了解 Android 系统的显示原理。

Android系统显示原理

Android 显示过程可以简单概括为:Android 应用程序把经过测量、布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上, 通过 Android 的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。

我们都知道在 Android 的每个 View 绘制中有三个核心步骤:Measure、Layout、Draw。具体实现是从 ViewRooTImp 类的performTraversals() 方法开始执行,Measure 和 Layout都是通过递归来获取 View 的大小和位置,并且以深度作为优先级,可以看出层级越深、元素越多、耗时也就越长。

真正把需要显示的数据渲染到屏幕上,是通过系统级进程中的 SurfaceFlinger 服务来实现的,那么这个SurfaceFlinger 服务主要做了哪些工作呢?如下: • 响应客户端事件,创建 Layer 与客户端的 Surface 建立连接。 • 接收客户端数据及属性,修改 Layer 属性,如尺寸、颜色、透明度等。 • 将创建的 Layer 内容刷新到屏幕上。 • 维持 Layer 的序列,并对 Layer 最终输出做出裁剪计算。

既然是两个不同的进程,那么肯定是需要一个跨进程的通信机制来实现数据传递,在 Android 显示系统中,使用了 Android 的匿名共享内存:SharedClient,每一个应用和 SurfaceFlinger 之间都会创建一个SharedClient ,然后在每个 SharedClient 中,最多可以创建 31 个 SharedBufferStack,每个 Surface 都对应一个 SharedBufferStack,也就是一个 Window。

一个 SharedClient 对应一个Android 应用程序,而一个 Android 应用程序可能包含多个窗口,即 Surface 。也就是说 SharedClient 包含的是 SharedBufferStack的集合,其中在显示刷新机制中用到了双缓冲和三重缓冲技术。最后总结起来显示整体流程分为三个模块:应用层绘制到缓存区,SurfaceFlinger 把缓存区数据渲染到屏幕,由于是不同的进程,所以使用 Android 的匿名共享内存 SharedClient 缓存需要显示的数据来达到目的。

除此之外,我们还需要一个名词:FPS。FPS 表示每秒传递的帧数。在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 以内。但是 Android 系统很有可能无法及时完成那些复杂的页面渲染操作。Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需的 60FPS。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就无法正常进行正常渲染,这样就发生了丢帧现象。那么用户在 32ms 内看到的会是同一帧画面,这种现象在执行动画或滑动列表比较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,无法在 16ms 完成渲染,最终引起刷新不及时。

卡顿根本原因

根据Android 系统显示原理可以看到,影响绘制的根本原因有以下两个方面:

• 绘制任务太重,绘制一帧内容耗时太长。 • 主线程太忙,根据系统传递过来的 VSYNC 信号来时还没准备好数据导致丢帧。

说到 Android 系统手机,大部分人的印象是用了一段时间就变得有点卡顿,有些程序在运行期间莫名其妙的出现崩溃,打开系统文件夹一看,发现多了很多文件,然后用手机管家 APP 不断地进行清理优化 ,才感觉运行速度稍微提高了点,就算手机在各种性能跑分软件面前分数遥遥领先,还是感觉无论有多大的内存空间都远远不够用。相信每个使用 Android 系统的用户都有过以上类似经历,确实,Android 系统在流畅性方面不如 IOS 系统,为何呢,明明在看手机硬件配置上时,Android 设备都不会输于 IOS 设备,甚至都强于它,关键是在于软件上。

造成这种现象的原因是多方面的,简单罗列几点如下:

• 其实近年来,随着 Android 版本不断迭代,Google 提供的Android 系统已经越来越流畅,目前最新发布的版本是 Android 8.0 Oreo 。但是在国内大部分用户用的 Android 手机系是各大厂商定制过的版本,往往不是最新的原生系统内核,可能绝大多数还停留在 Android 5.0 系统上,甚至 Android 6.0 以上所占比例还偏小,更新存在延迟性。

• 由于 Android 系统源码是开放的,每个人只要遵从相应的协议,就可以对源码进行修改,那么国内各个厂商就把基于 Android 源码改造成自己对外发布的系统,比如我们熟悉的小米手机 Miui 系统、华为手机 EMUI 系统、Oppo 手机 ColorOS 系统等。由于每个厂商都修改过 Android 原生系统源码,这里面就会引发一个问题,那就是著名的Android 碎片化问题,本质就是不同 Android 系统的应用兼容性不同,达不到一致性。

• 由于存在着各种 Android 碎片化和兼容性问题,导致 Android 开发者在开发应用时需要对不同系统进行适配,同时每个 Android 开发者的开发水平参差不齐,写出来的应用性能也都存在不同类型的问题,导致用户在使用过程中用户体验感受不同,那么有些问题用户就会转化为 Android 系统问题,进而影响对Android 手机的评价。

性能优化

今天想说的重点是Android APP 性能优化,也就是在开发应用程序时应该注意的点有哪些,如何更好地提高用户体验。一个好的应用,除了要有吸引人的功能和交互之外,在性能上也应该有高的要求,即时应用非常具有特色,在产品前期可能吸引了部分用户,但是用户体验不好的话,也会给产品带来不好的口碑。

那么一个好的应用应该如何定义呢?主要有以下三方面: • 业务/功能 • 符合逻辑的交互 • 优秀的性能

众所周知,Android 系统作为以移动设备为主的操作系统,硬件配置是有一定的限制的,虽然配置现在越来越高级,但仍然无法与 PC 相比,在 CPU 和内存上使用不合理或者耗费资源多时,就会碰到内存不足导致的稳定性问题、CPU 消耗太多导致的卡顿问题等。

面对问题时,大家想到的都是联系用户,然后查看日志,但殊不知有关性能类问题的反馈,原因也非常难找,日志大多用处不大,为何呢?因为性能问题大部分是非必现的问题,问题定位很难复现,而又没有关键的日志,当然就无法找到原因了。这些问题非常影响用户体验和功能使用,所以了解一些性能优化的一些解决方案就显得很重要了,并在实际的项目中优化我们的应用,进而提高用户体验。

四个方面

可以把用户体验的性能问题主要总结为4个类别: • 流畅 • 稳定 • 省电、省流量 • 安装包小

性能问题的主要原因是什么,原因有相同的,也有不同的,但归根到底,不外乎内存使用、代码效率、合适的策略逻辑、代码质量、安装包体积这一类问题,整理归类如下:

从图中可以看到,打造一个高质量的应用应该以4个方向为目标:快、稳、省、小。

快:使用时避免出现卡顿,响应速度快,减少用户等待的时间,满足用户期望。

稳:减低 crash 率和 ANR 率,不要在用户使用过程中崩溃和无响应。

省:节省流量和耗电,减少用户使用成本,避免使用时导致手机发烫。

小:安装包小可以降低用户的安装成本。

要想达到这4个目标,具体实现是在右边框里的问题:卡顿、内存使用不合理、代码质量差、代码逻辑乱、安装包过大,这些问题也是在开发过程中碰到最多的问题,在实现业务需求同时,也需要考虑到这点,多花时间去思考,如何避免功能完成后再来做优化,不然的话等功能实现后带来的维护成本会增加。

卡顿优化

Android 应用启动慢,使用时经常卡顿,是非常影响用户体验的,应该尽量避免出现。卡顿的场景有很多,按场景可以分为4类:UI 绘制、应用启动、页面跳转、事件响应,如图:

这4种卡顿场景的根本原因可以分为两大类:

• 界面绘制。 主要原因是绘制的层级深、页面复杂、刷新不合理,由于这些原因导致卡顿的场景更多出现在 UI 和启动后的初始界面以及跳转到页面的绘制上。

• 数据处理。 导致这种卡顿场景的原因是数据处理量太大,一般分为三种情况: 一是数据在处理 UI 线程, 二是数据处理占用 CPU 高,导致主线程拿不到时间片, 三是内存增加导致 GC 频繁,从而引起卡顿。 引起卡顿的原因很多,但不管怎么样的原因和场景,最终都是通过设备屏幕上显示来达到用户,归根到底就是显示有问题,所以,要解决卡顿,就要先了解 Android 系统的显示原理。

Android系统显示原理

Android 显示过程可以简单概括为:Android 应用程序把经过测量、布局、绘制后的 surface 缓存数据,通过 SurfaceFlinger 把数据渲染到显示屏幕上, 通过 Android 的刷新机制来刷新数据。也就是说应用层负责绘制,系统层负责渲染,通过进程间通信把应用层需要绘制的数据传递到系统层服务,系统层服务通过刷新机制把数据更新到屏幕上。

我们都知道在 Android 的每个 View 绘制中有三个核心步骤:Measure、Layout、Draw。具体实现是从 ViewRooTImp 类的performTraversals() 方法开始执行,Measure 和 Layout都是通过递归来获取 View 的大小和位置,并且以深度作为优先级,可以看出层级越深、元素越多、耗时也就越长。

真正把需要显示的数据渲染到屏幕上,是通过系统级进程中的 SurfaceFlinger 服务来实现的,那么这个SurfaceFlinger 服务主要做了哪些工作呢?如下: • 响应客户端事件,创建 Layer 与客户端的 Surface 建立连接。 • 接收客户端数据及属性,修改 Layer 属性,如尺寸、颜色、透明度等。 • 将创建的 Layer 内容刷新到屏幕上。 • 维持 Layer 的序列,并对 Layer 最终输出做出裁剪计算。

既然是两个不同的进程,那么肯定是需要一个跨进程的通信机制来实现数据传递,在 Android 显示系统中,使用了 Android 的匿名共享内存:SharedClient,每一个应用和 SurfaceFlinger 之间都会创建一个SharedClient ,然后在每个 SharedClient 中,最多可以创建 31 个 SharedBufferStack,每个 Surface 都对应一个 SharedBufferStack,也就是一个 Window。

一个 SharedClient 对应一个Android 应用程序,而一个 Android 应用程序可能包含多个窗口,即 Surface 。也就是说 SharedClient 包含的是 SharedBufferStack的集合,其中在显示刷新机制中用到了双缓冲和三重缓冲技术。最后总结起来显示整体流程分为三个模块:应用层绘制到缓存区,SurfaceFlinger 把缓存区数据渲染到屏幕,由于是不同的进程,所以使用 Android 的匿名共享内存 SharedClient 缓存需要显示的数据来达到目的。

除此之外,我们还需要一个名词:FPS。FPS 表示每秒传递的帧数。在理想情况下,60 FPS 就感觉不到卡,这意味着每个绘制时长应该在16 ms 以内。但是 Android 系统很有可能无法及时完成那些复杂的页面渲染操作。Android 系统每隔 16ms 发出 VSYNC 信号,触发对 UI 进行渲染,如果每次渲染都成功,这样就能够达到流畅的画面所需的 60FPS。如果某个操作花费的时间是 24ms ,系统在得到 VSYNC 信号时就无法正常进行正常渲染,这样就发生了丢帧现象。那么用户在 32ms 内看到的会是同一帧画面,这种现象在执行动画或滑动列表比较常见,还有可能是你的 Layout 太过复杂,层叠太多的绘制单元,无法在 16ms 完成渲染,最终引起刷新不及时。

卡顿根本原因

根据Android 系统显示原理可以看到,影响绘制的根本原因有以下两个方面:

• 绘制任务太重,绘制一帧内容耗时太长。 • 主线程太忙,根据系统传递过来的 VSYNC 信号来时还没准备好数据导致丢帧。

技术专区 Android 系统性能优化问题及显示原理 RobotStudio随真实控制器安装选项及应用 检测内存泄漏和内存违例,Valgrind不可少! C语言程序内存布局该关注哪些内容 DSP/BIOS嵌入式实时操作系统介绍及其引导设计
免责声明:本文由用户上传,如有侵权请联系删除!