Android 稳定性优化总结

news/2025/2/10 23:49:20/

对稳定性的理解

应用稳定性是最重要的性能指标之一,是APP质量构建体系中的基本盘,如果应用的稳定性出现问题,对产品、用户造成的伤害将是致命的。本文将从以下几个方面对应用稳定性优化进行整理。

需要说明,广义的稳定性不仅仅是崩溃问题,还包括卡顿、耗电、温度等指标,本文主要从崩溃率的角度进行学习。

稳定性常见指标分类:业界用来衡量稳定性的常见指标,稳定性优秀的衡量标准。处理Crash的一般步骤:发生Crash时常规的处理步骤。业务高可用性建设:在维护一整块业务时,为了防止出现稳定性问题,所采用的手段。长效治理Crash:在更长的周期内如何防止稳定性劣化。面试常见问题:面试中关于稳定性的常见问题。

稳定性常见指标分类

异常分类:Exception与ANR

Android的崩溃问题可以分为Exception、ANR两类。

Exception:应用内部代码发生异常

JE:Java Exception,在Java代码中发生未捕获的异常NE:Native Exception,在Native代码中访问非法地址,程序主动abort等

ANR:应用无响应,不一定是代码逻辑导致的

JE、NE、ANR既可以独立统计,也可以汇总后作为总体崩溃率。

PV与UV

是衡量应用软件使用量的指标。

PV:Page View,指页面的全部展示量,不区分用户,如果一名用户打开了100次页面,PV=100UV:Unique View,指对用户去重后的访问量统计,如果一名用户打开了100次页面,UV=1

因此,崩溃率在PV和UV两个维度上都可以进行统计。

PV Crash:评估问题影响严重程度UV Crash:评估问题在用户群体内影响范围

增量崩溃率与存量崩溃率

增量崩溃:由当前新增代码导致的崩溃,是导致大盘崩溃率发生波动的主要原因。要早发现早解决,避免带到线上成为存量崩溃。处理策略:重要且紧急存量崩溃:由存量代码引起,是需要持续跟进的问题,解决存量崩溃有助于拉低线上大盘的崩溃率。处理策略:重要不紧急

崩溃率评价指标

统计口径:

分子:JE+NE+ANR 发生总次数分母:PV

<2‰为合格,<1‰(万级)为优秀。

处理Crash的一般步骤

在处理Crash时,分为采集现场数据和分析崩溃原因两个步骤。

采集现场数据

能够复现的崩溃才是好崩溃

在处理崩溃时,采集现场信息是至关重要的,现场保留着很多有价值的线索,是我们进一步排查的风向标。

根据层级的不同,将现场信息分为:崩溃本身、运行时状态、系统状态三个层级。

一些成熟的崩溃采集平台(如bugly、Sentry)可以cover以下大部分内容,但应用开发者仍然需要上传用户操作日志等自定义信息。

崩溃本身

主要是崩溃堆栈和进程、线程信息。

崩溃堆栈:这是最重要的信息,反映了崩溃时函数的调用栈。如果代码经过混淆,堆栈信息里的内容需要经过反混淆后才能进行分析,因此保存打包时的mapping文件至关重要进程与线程信息:崩溃的进程是哪一个,处于前台还是后台,线程是UI线程还是工作线程

运行时状态

内存信息

系统内存占用情况:/proc/meminfo记录了系统实时的内存状态,当系统可用内存低于总内存的10%时,会频繁发生GC,导致OOM、ANR等问题应用内存使用情况:PSS、RSS(这部分知识可查看juejin.cn/post/735989… 进一步了解),得知应用当时物理内存占用情况;虚拟内存的信息则保存在/proc/self/status中,其具体分布则需要查看/proc/self/maps

应用操作路径:应用本身应该通过埋点、日志等记录用户的操作路径,当前打开的页面,正在运行的服务等应用信息:应用版本,是否经过热修复,CPU架构文件信息:文件句柄fd的打开量,单进程最大允许打开的fd数量是1024,超过800则处于危险状态,需要将所有fd即对应的文件名进行记录并上报线程信息:单个线程会占用大约2MB虚拟内存,现成总量超过400则危险,需要上报所有线程id、name

系统状态

系统硬件信息:CPU,ABI,内存总量,网络连接状态系统软件信息:Android版本、Linux内核版本、WebView内核版本,OEM软件版本,是否root,是否模拟器系统日志:Logcat、EventLog等

分析崩溃原因

这一步也就是解析Crash,在分析时有种仿佛化身为一名侦探,抽丝剥茧侦查犯罪现场,定位嫌疑人的感觉。

第一步:单点突破

针对单条崩溃日志进行细致分析。

确认严重程度:是会导致应用闪退,还是当前页面功能不可用,接口请求失败,又或者是用户根本无感知确认优先级:根据严重程度确定处理优先级,优先级高的应当先处理观察收集到的崩溃基本信息,注意那些Android版本兼容性导致的异常,可能在新版本不会有问题,但老版本Android就会崩溃。根据崩溃类型不同,浏览信息的侧重点有所不同:

JE:90%的异常通过堆栈可以找出调用关系,特别指出,对于OOM则要关注内存占用情况NE:观察signal、code、fault addr等内容,崩溃信号signal的定义可见官方文档,其中SIGSEGV(空指针、非法指针)和SIGABRT(ANR、abort()调用)较为常见ANR:先观察trace.txt文件,重点查看主线程状态、是否持有锁,IO信息和CPU占用信息,以及GC回收前后的状态

观察Logcat日志:尤其是Warning、Error级别的,对于ANR则需要搜索am_anr的关键字资源使用情况:如内存(物理+虚拟)、文件句柄、线程数量

第二步:群体聚合

对于后台聚合完成的崩溃信息,查看它们有没有共性,可用于排查的共性有:

机型,Android版本,Rom版本,厂商,ABI,是否root,是否虚拟机,网络状态,当前打开的页面,进程状态,后台正在运行的服务等。尤其是Android系统版本,很容易出现由于版本变更导致原来可用的代码发生崩溃,或者一个功能只在高版本Android正常运行,在低版本则有概率崩溃。我曾经处理过一个例子是显示Toast时偶现BadTokenException,就是在8.0以下才会发生的。

稳定性长期治理

根据所处流程,采取不同的稳定性优化策略

开发阶段

开发是质量的第一道关卡,问题发现得越早,修复成本就越低统一编码规范,增强编码安全教育,增强代码评审,进行结对编程等代码架构优化,对常用能力、底层功能进行模块封装与复用,设计单元测试,对于接口返回失败等情况进行统一的收口与错误处理

测试阶段

新功能测试:本次新增功能,以及新增功能所影响到的部分主流程回归测试:核心流程覆盖安装测试:覆盖安装老版本过程中,缓存、数据库等应当兼容兼容性测试:不仅是本公司手机,还有安装应用到第三方手机的场景边界条件:如服务器宕机、返回数据异常、弱网和无网情况

代码合并阶段

冲突处理:如果代码有冲突则优先处理冲突,尤其是依赖的第三方库,如果不同的分支引入了不同版本,在合入代码时应当确认最终版本能够满足不同分支的需求编译检查:处理完冲突后,打包安装并回归主流程,静态扫描:借助lint等工具进行代码静态扫描,发现潜在的风险点自动化测试:如果项目有集成Appium等自动化测试框架,则应当在合并代码后自动执行

发布阶段

采取灰度策略,先在小范围小量级内投放新版本升级,逐步扩大升级覆盖的用户范围,当灰度版本的稳定性、业务数据等指标合格后(不低于大盘5%),才进行全量发布。进行多轮灰度,并且可以根据特定机型、OS版本进行专门灰度,防止特定条件下的问题发生采取ABTest策略:灰度时通过发布一个新功能包+一个对比包,来进行稳定性、业务数据的比对。之所以不采用线上全量版本作为对比包,是因为两者量级不同,在一些数据上的表现会有差异。而ABTest则通过控制两者具有相同的量级,防止这方面差异的产生。同时,可以在指定的系统版本、机型、用户群体上进行有针对性的ABTest

运营阶段

应用上线后持续关注线上稳定性波动,采用日报等方式进行监控,当崩溃率在超出阈值、或趋势发生波动时,及时报警通知相关方当发生无法规避的异常时,采取回滚和降级策略(参考下文的“业务高可用性方案建设”一节)版本前期关注增量异常,在处理完增量异常后,定期对存量异常进行整治,以期降低大盘崩溃率

业务高可用性方案建设

稳定性优化不仅仅要降低崩溃率,其根本目标是保证业务的高可用性。有时代码里发生异常后,虽然应用没有崩溃,但业务上处于一个不可用的状态,比如页面跳转失败、接口请求失败后无重试,等等。这些场景也是我们竭力要避免的。

要提高业务的可用性,有以下思路:

梳理业务流程,对于关键和核心路径进行埋点统计,尤其是页面加载成功率、下载安装成功率等通过AOP等方式进行无侵入数据采集,既可以全面覆盖防止遗漏,还能降低开发成本建立数据大盘,采用IM消息、每日邮件等方式,推送给利益相关者。数据可以分为业务数据和技术数据两类建立报警策略,通常有以下几种

阈值报警:某项指标的绝对值,如登录成功率、支付成功率、未导致崩溃的异常发生率趋势报警:相比同期的变化特定指标报警:单次发生即上报,如支付失败

针对特定用户的问题,如果在测试、开发环境难以复现,可以对其采取全量日志回捞的方式进行信息采集发现异常后,采用兜底策略降低损失

在配置中心通过设置开关,关闭相应功能入口如果是服务器下发的跳转参数,可以在服务器下发数据时,修改为跳转到正常页面采用热修复等方式替换掉异常逻辑

客户端容灾方案建设

针对异常导致的崩溃,如果我们在收到线上用户反馈后,采用本地调试、开发、测试、上线、灰度、全量的处理流程,周期是比较长的,在这期间问题的影响可能会进一步增大,而问题影响人数是线上事故定级的重要参考指标,因此不能完全依赖传统开发流程来做容灾方案。

新功能配置开关:对于新开发的重要功能,可以在全局配置接口增加开关,当线上该功能发生稳定性问题(不一定是客户端导致,也有可能是服务器、网络运营商等原因),关闭开关,隐藏功能入口动态配置路由:动态下发路由表,将问题页面导向默认的错误处理页等热修复:通过热修复来替换掉问题类动态化:如果项目使用的是RN、Weex或者Flutter,则借助其动态化能力进行更新安全模式兜底:参考天猫的安全方案,当应用在启动阶段就发生异常时,进行计数,达到阈值则清空应用数据


http://www.ppmy.cn/news/1570998.html

相关文章

Ubuntu下npm运行报错Error: Cannot find module ‘node:path‘

执行了apt install npm安装了npm&#xff0c;然后又执行 npm install -g npm更新了一下&#xff0c;执行 npm run serve 出现奇怪现象&#xff0c;在安装npm的终端里执行这个命令就可以运行&#xff0c;再打开一个新的终端在同样的环境下执行这个命令就是报错&#xff0c;执行…

百度的冰桶算法

百度的冰桶算法&#xff08;Ice Bucket Algorithm&#xff09;是百度搜索引擎用于打击低质量内容的一种算法。该算法主要针对那些通过大量堆砌关键词、内容质量低下、用户体验差的网页进行惩罚&#xff0c;从而提升搜索结果的质量。 冰桶算法的核心目标&#xff1a; 打击低质…

win10 llamafactory模型微调相关① || Ollama运行微调模型

目录 微调相关 1.微调结果评估 2.模型下载到本地 导出转换&#xff0c;Ollama运行 1.模型转换&#xff08;非常好的教程&#xff01;&#xff09; 2.Ollama 加载GGUF模型文件 微调相关 1.微调结果评估 【06】LLaMA-Factory微调大模型——微调模型评估_llamafactory评估-C…

Docker 数据卷(Volume)详细介绍

Docker 数据卷&#xff08;Volume&#xff09;详细介绍 1. 什么是 Docker 数据卷&#xff1f; Docker 数据卷&#xff08;Volume&#xff09;是一种用于 持久化数据 和 容器间数据共享 的机制。由于容器的存储是临时的&#xff0c;容器删除后其中的数据会丢失&#xff0c;因此…

让文物“活”起来,以3D数字化技术传承文物历史文化!

文物&#xff0c;作为不可再生的宝贵资源&#xff0c;其任何毁损都是无法逆转的损失。然而&#xff0c;当前文物保护与修复领域仍大量依赖传统技术&#xff0c;同时&#xff0c;文物管理机构和专业团队的力量相对薄弱&#xff0c;亟需引入数字化管理手段以应对挑战。 积木易搭…

周报1.0

补题补题(///&#xffe3;皿&#xffe3;)○&#xff5e; 牛客1(4):ABDG E:双生双宿之错: 小红定义一个数组是“双生数组”&#xff0c;当且仅当该数组大小为偶数&#xff0c;数组的元素种类恰好为 2种&#xff0c;且这两种元素的出现次数相同。例如{1,1,4,4,1,4} 是双生数组…

【JavaEE】Spring Web MVC

目录 一、Spring Web MVC简介 1.1 MVC简介1.2 Spring MVC1.3 RequestMapping注解1.3.1 使用1.3.2 RequestMapping的请求设置 1.3.2.1 方法11.3.2.2 方法2 二、Postman介绍 2.1 创建请求2.2 界面如下&#xff1a;2.3 传参介绍 一、Spring Web MVC简介 官方文档介绍&#xff…

从 SQL 语句到数据库操作

1. SQL 语句分类 数据定义语言 DDL &#xff1a; 用于定义或修改数据库中的结构&#xff0c;如&#xff1a;创建、修改、删除数据库对象。create、drop alter 数据操作语言 DML &#xff1a; 用于添加、删除、更新数据库中的数据。select、insert alter、drop 数据控制语言 D…