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

建立分位制,用标准去量化优化效果 - 启动优化为例

Android开发的四年多时间中,逐渐将自己的工作重心从业务移动到小型项目的架构设计,在此过程中代码的书写有了更高的标准和要求,性能优化从此伴随着工作脚步, 为什么要进行性能优化呢?

  • 页面访问时长从1s增加到3s,用户跳出率增加32%
  • 崩溃率直接影响用户留存
  • 卡顿会让用户选择放弃
    等等

在互联网蓝海逐渐缩小的时代,圈人依然是每个互联网公司的目标,当有足够大的使用人数时变现、营销等都将能实现,所以提升用户体验是不可或缺的部分

背景:
在团队开发中,如何定义优化的效果,我想是可以进行量化的,将自己的应用的各个部分进行解体,完全掌握,然后和业内特别是竞品进行比较,做到知己知彼,才能百战百胜。

以下以启动优化作为案例:

一、建立启动优化耗时标准

针对优化我们需要知道优化的当前目标和优化后的目标是多少?该目标就是 — 启动耗时

3.1 统计启动耗时

很多应用把启动结束时间的统计放到首页刚出现的时候,这对用户是不负责任的,看到一个首页,但是停住十几秒都不能滑动,这对用户来说完全没有意义 ,所以我们需要着眼于从点击图标到用户可操作的整个过程

3.2 建立分位置
  1. 比如应用启动耗时从500ms~1500ms对应分为值为100 ~ 0(分)

比如应用启动耗时80分位值为我们APP的标准启动耗时分位值,而80分位值的对应时间为600ms, 所有用户的启动分位值计算出满足80分位值的用户,占比就说明有多少的情况下用户启动APP都能在 600ms 内完成,而我们需要做的就是让更多的用户达到指定的分位值。

  1. 此时我们通过在线上打点统计用户实际的启动耗时、机型归属(确定低、中、高端机)

(以下为假设APP启动机型和分位值统计所得数据)

机型归属分位值人数
2008901000
2009701200
201060200
2011803000
2012204000
2013804500
2014903000
2015903000
2016904000
2017808000
20187010000
20199012000
20208820000
20218710000
20229810000

(以下为数据对应图表)

(以下针对上述图表进行结论总结)

  • 达到分位值的用户

总人数为93900人,达标用户总数为78500人,其中高端机用户为74500人,低端机用户为4000人

达标率 = 78500/93900 ≈ 84%

低端机占比 = 4000 / 78500 ≈ 5%

总人数:

达标用户

其中高端机

低端机占比

至此我们就知道了应用目前的情况

一、启动过程分析

  • T1 预览窗口显示

系统在拉起进APP程之前,会先根据APP的 Theme 属性创建预览窗口。当然如果我们禁用预览窗口或者将预览窗口指定为透明,用户在这段时间依然看到的是桌面。(用户可能觉得是手机卡顿而非应用卡顿)

  • T2 闪屏显示

在APP进程和闪屏窗口页面创建完毕,并且完成一系列 inflate view、onmeasure、onlayout 等准备工作后,用户终于可以看到欢迎页面。

  • T3 主页显示

在完成主窗口创建和页面显示的准备工作后,用户可以看到APP的主界面。

  • T4 界面可以操作

在启动完成后,APP会有比较多的工作需要继续执行(初始化的东西按需分配至不同阶段),(比如微信聊天和朋友圈界面的预加载、小程序框架和进程的准备等。在这些工作完成后,用户才可以真正开始愉快地聊天。)

二、启动问题分析

以上4个启动的关键阶段,可以推测一下启动过程中越到的问题和平常在使用中会出现的问题相结合,基本为以下三个:

  • 点击图标之后很久不响应

如果我们禁用了预览窗口或者指定了透明的皮肤,那用户点击了图标之后,需要 T2 时间才能真正看到应用闪屏。对于用户体验来说,点击了图标,过了几秒还是停留在桌面,看起来就像没有点击成功,这在中低端机中更加明显。

  • 首页显示太慢

现在应用启动流程越来越复杂,闪屏广告、热修复框架、插件化框架、大前端框架,所有准备工作都需要集中在启动阶段完成。上面说的 T3 首页显示时间对于中低端机来说简直就是噩梦,经常会达到十几秒的时间。

  • 首页显示后无法操作

既然首页显示那么慢,那我能不能把尽量多的工作都通过异步化延后执行呢?很多应用的确就是这么做的,但这会造成两种后果:要么首页会出现白屏,要么首页出来后用户根本无法操作。

四、优化工具

对于优化Android拥有非常多的优化工具,Traceview、Nanoscope (非常真实,不过暂时只支持 Nexus 6P 和 x86 模拟器,无法针对中低端机做测试)。

systrace 可以很方便地追踪关键系统调用的耗时情况,但是不支持应用程序代码的耗时分析。

综合来看,“systrace + 函数插桩”似乎是比较理想的方案,而且它还可以看到系统的一些关键事件,例如 GC、System Server、CPU 调度等。

  • 查看支持的类型
python systrace.py --list-categories

通过插桩,我们可以看到应用主线程和其他线程的函数调用流程。它的实现原理非常简单,就是将下面的两个函数分别插入到每个方法的入口和出口。


class Trace {public static void i(String tag) {Trace.beginSection(name);}public static void o() {Trace.endSection();}
}

当然这里面有非常多的细节需要考虑,比如怎么样降低插桩对性能的影响、哪些函数需要被排除掉(可在debug环境下使用)

只有准确的数据评估才能指引优化的方向,这一步是非常非常重要的。

五、优化方式

在拿到整个启动流程的全景图之后,我们可以清楚地看到这段时间内系统、应用各个进程和线程的运行情况

可分为以下优化模块:

5.1 闪屏优化
  1. 预览窗口window属性设置,让体验出现跟手感觉
  1. 合并闪屏和主页面的Activity,减少一个Activity会给线上带来100ms的优化 (管理复杂)
5.2 业务梳理

我们首先需要梳理清楚

  • 当前启动过程正在运行的每一个模块,哪些是一定需要的、哪些可以砍掉、哪些可以懒加载。
  • 可以根据业务场景来决定不同的启动模式,例如通过扫一扫启动只需要加载需要的几个模块即可。对于中低端机器,我们要学会降级,学会推动产品经理做一些功能取舍。但是需要注意的是,懒加载要防止集中化,否则容易出现首页显示后用户无法操作的情形。
5.3 线程优化
  1. 线程优化就像做填空题和解锁题,我们希望能把所有的时间片都利用上,因此主线程和各个线程都是一直满载的。当然我们也希望每个线程都开足马力向前跑,而不是作为接力棒。所以线程的优化主要在于减少 CPU 调度带来的波动,让应用的启动时间更加稳定

从具体的做法来看,线程的优化一方面是控制线程数量,线程数量太多会相互竞争 CPU 资源,因此要有统一的线程池,并且根据机器性能来控制数量。

线程切换的数据我们可以通过卡顿优化中学到的 sched 文件查看,这里特别需要注意 nr_involuntary_switches 被动切换的次数。

可以使用命令

proc/[pid]/sched
  • 其中:
    • nr_voluntary_switches: 主动上下文切换次数,因为线程无法获取所需资源导致上下文切换,最普遍的是IO。
    • nr_involuntary_switches: 被动上下文切换次数,线程被系统强制调度导致上下文切换,例如大量线程在抢占CPU。
  1. 另一方面是检查线程间的锁

各APP做启动优化时并行初始化是优化的手段之一,但是有的情况下并发初始化会因为书写而不起作用

线程内部会持有一个锁,主线程很快就执行完了,其他任务因为这个锁而等待。这样的话主线程就出现了空转的场景,可以通过systrace看锁等待事件,我们要以此排查是否需要做对应的优化

在做初始化优化时,一般会将业务进行优先级区分,业务优先级规定业务初始化的时机,比较火的启动框架大多采用:为各个人物建立依赖关系,最终构成一个有向无环图,对于可以并发的任务,会通过线程池最大程度提升启动速度。

当出现并-总模式时,配置不恰当就会出现以下问题:

即:主线程一直等待taskC 结束,空转2950ms

5.4 GC优化

在启动过程,要尽量减少 GC 的次数,避免造成主线程长时间的卡顿,特别是对 Dalvik 来说,我们可以通过 systrace 单独查看整个启动过程 GC 的时间。

python systrace.py dalvik -b 90960 -a com.sample.gc

也可以采用Debug.startAllocCounting 来监控启动过程中GC的耗时情况,特别是阻塞式同步 GC 的总次数和耗时


// GC使用的总耗时,单位是毫秒
Debug.getRuntimeStat("art.gc.gc-time");
// 阻塞式GC的总耗时
Debug.getRuntimeStat("art.gc.blocking-gc-time");

如果我们发现主线程出现比较多的 GC 同步等待,那就需要通过 Allocation 工具做进一步的分析启动过程避免进行大量的字符串操作,特别是序列化跟反序列化过程。一些频繁创建的对象,例如网络库和图片库中的 Byte 数组、Buffer 可以复用。如果一些模块实在需要频繁创建对象,可以考虑移到 Native 实现。

Java 对象的逃逸也很容易引起 GC 问题,我们在写代码的时候比较容易忽略这个点。我们应该保证对象生命周期尽量的短,在栈上就进行销毁。

Java 逃逸分析 https://segmentfault.com/a/1190000016803174

5.5 系统调用优化
  • 通过 systrace 的 System Service 类型,我们可以看到启动过程 System Server 的 CPU 工作情况。在启动过程,我们尽量不要做系统调用,例如 PackageManagerService 操作、Binder 调用等待。
  • 在启动过程也不要过早地拉起应用的其他进程,System Server 和新的进程都会竞争 CPU 资源。特别是系统内存不足的时候,当我们拉起一个新的进程,可能会成为“压死骆驼的最后一根稻草”。它可能会触发系统的 low memory killer 机制,导致系统杀死和拉起(保活)大量的进程,从而影响前台进程的 CPU。

在我们应用中IM进程和File下载进程的拉起时机需要做调整

5.6 高级性能优化

可以更多的参考腾讯的matrix, 从性能的根本问题上进行了解决 https://github.com/Tencent/matrix

设备分级:

上文提到的设备分级,在这里说明一下

核心思想:

设备分级是指Device-year-class ,它是Facebook 开源的一个Android库,实现原理是将一个手机的内存(RAM)、CPU内存和clock speed((主频)时钟速度)三个方面映射到指定的一个组合中,通过这个验证来判断你是那一年的,规格的高低决定你是”那一年“的而不是手机的生产年份。(当然我们可以根据自己的需求定义这些参数,比如音视频公司可以从CPU、GPU等音视频相关参数出发定位等)

实现流程图
image.png

作用

针对机型进行适配,让每一份努力都能展现到对应的用户面前

相关文章:

建立分位制,用标准去量化优化效果 - 启动优化为例

Android开发的四年多时间中,逐渐将自己的工作重心从业务移动到小型项目的架构设计,在此过程中代码的书写有了更高的标准和要求,性能优化从此伴随着工作脚步, 为什么要进行性能优化呢? 页面访问时长从1s增加到3s&#…...

Modbus 通信协议 二

Modbus 常用缩写 通用Modbus帧结构 -应用数据单元(ADU) Modbus数据模型 Modbus ADU 和 PDU 的长度 Modbus PDU结构 串行链路上的 Modbus 帧结构 Modbus 地址规则 ASCLL 模式 和 RTU 模式的比较 RTU 模式 RTU 模式位序列 帧格式 帧的标识与鉴别 CRC 循环冗…...

关于系统设计的一些思考

0.前言 当我们站在系统设计的起点,面对一个新的需求,我们该如何开始呢?这是许多处于系统分析与设计领域的新手常常思考的问题。有些人可能会误以为,只要掌握了诸如面向对象、统一建模语言、设计模式、微服务、Serverless、Servic…...

Java 第19章 IO流 课堂练习+本章作业

文章目录 Buffered流拷贝二进制文件创建文件写入文本读取文本文件存读Properties文件 Buffered流拷贝二进制文件 package com.hspedu.chapter19.outputStream;import java.io.*;public class BufferedCopy02 {public static void main(String[] args) {String srcFilePath &q…...

一键制作电子样册,提升企业品牌形象

​电子样册作为一种新型的宣传方式,具有许多优势。首先,它打破了传统纸质宣传册的局限性,可以随时随地展示企业的产品和服务。其次,电子样册可以通过多媒体形式展示企业的品牌形象,包括图片、视频、文字等多种形式&…...

Linux 的引导与服务控制

一 开机启动过程 bios加电自检-->mbr-->grub-->加载内核文件-->启动进程 1 bios家电自检 检测硬件是否正常,然后根据bios中的启动项设置,去找内核文件 2 mbr 因为grup太大,第一个扇区存不下所有的grub程序,所以分为2部分指…...

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测

多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测 目录 多输入多输出 | MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入多输出预测预测效果基本介绍模型背景程序设计参考资料 预测效果 基本介绍 MATLAB实现SSA-CNN麻雀算法优化卷积神经网络多输入…...

高端电流检测方案

随着过去传统的“开环”系统被智能和高效率“闭环”设计所取代,准确的电流检测在多种应用中变得越来越重要。常见的电流检测方法,需要将检流电阻串联进被测电流通路,再用放大电路放大检流电阻上的压降。这个放大电路常被称之为电流检测放大器…...

IP地址、子网掩码与网络地址

一、IP地址 在 TCP/IP 体系中,IP 地址是一个最基本的概念。IP地址的作用:实现和网上的其他设备进行通信 IP地址的表示方法 互联网上的每台主机(或路由器)的每个接口都分配一个全世界唯一的IP地址。该IP地址由ICANN分配。 IP地址…...

python 深度学习 记录遇到的报错问题10

本篇继python 深度学习 解决遇到的报错问题9_module d2l.torch has no attribute train_ch3-CSDN博客 一、CUDA error: no kernel image is available for execution on the device CUDA kernel errors might be asynchronously reported at some other API call,so the stackt…...

linux下docker搭建Prometheus +SNMP Exporter +Grafana进行核心路由器交换机监控

一、安装 Docker 和 Docker Compose https://docs.docker.com/get-docker/ # 安装 Docker sudo apt-get update sudo apt-get install -y docker.io# 安装 Docker Compose sudo apt-get install -y docker-compose二、创建配置文件及测试平台是否正常 1、选个文件夹作为自建…...

Github 2023-12-31 开源项目日报 Top10

根据Github Trendings的统计,今日(2023-12-31统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量TypeScript项目3Swift项目1Java项目1HTML项目1Astro项目1Python项目1C项目1Dart项目1Jupyter Notebook项目1C项…...

管程-第三十三天

目录 为什么要引入管程 管程的定义和基本特征 用管程解决生产者消费者问题 结论 本节思维导图 为什么要引入管程 原因:在解决进程的同步与互斥问题时,信号量机制存在编写困难和易出错的问题 能不能设计一种机制,让程序员写程序时不再需…...

嵌入式中断理解

一、概念 中断: 在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行。 中断优先级&#x…...

React16源码: Hooks源码实现

Hooks 1 )概述 Hooks 在 React16.7版本出现的新功能Hooks 改变了整体应用开发的模式,同时开发体验会和以前会变得不一样Hooks 让函数组件具有类组件的能力 在 function component 里面没有this无法保存 state通过 Hooks可以让 function component 代替…...

华为端口隔离高级用法经典案例

最终效果: pc4不能ping通pc5,pc5能ping通pc4 pc1不能和pc2、pc3通,但pc2和pc3能互通 vlan batch 2 interface Vlanif1 ip address 10.0.0.254 255.255.255.0 interface Vlanif2 ip address 192.168.2.1 255.255.255.0 interface MEth0/0/1 i…...

java项目启动jar包启动参数设置端口号

默认启动 java -jar myapp.jar 指定配置文件 java -jar myapp.jar --spring.profiles.activedev 指定端口号 java -jar myapp.jar --server.port8080 后台启动 nohup java -jar myapp.jar --server.port8080 >outlog.log 2>&1 &...

【数据结构和算法】寻找数组的中心下标

其他系列文章导航 Java基础合集数据结构与算法合集 设计模式合集 多线程合集 分布式合集 ES合集 文章目录 其他系列文章导航 文章目录 前言 一、题目描述 二、题解 2.1 前缀和的解题模板 2.1.1 最长递增子序列长度 2.1.2 寻找数组中第 k 大的元素 2.1.3 最长公共子序列…...

多粒度在研究中的应用

FontDiffuser: One-Shot Font Generation via Denoising Diffusion with Multi-Scale Content Aggregation and Style Contrastive Learning 存在的问题 现有的字体生成方法虽然取得了令人满意的性能,但在处理复杂字和风格变化较大的字符(尤其是中文字符)时&#x…...

Docker命令---查看容器日志

介绍 使用docker命令查看容器输出的日志 示例 docker logs 容器ID...

Spring Boot 基于Redisson实现注解式分布式锁

依赖版本 JDK 17 Spring Boot 3.2.0 Redisson 3.25.0 源码地址&#xff1a;Gitee 导入依赖 <properties><redisson.version>3.25.0</redisson.version> </properties><dependencies><dependency><groupId>org.projectlombok</…...

Javascript 正则表达式零宽断言

在介绍正则表达式零宽断言这个概念之前&#xff0c;先看一下以下这道有关 javascript 正则表达式的题目&#xff1a; 登录注册流程是前端最常见的业务流程之一&#xff0c;注册流程少不了密码强弱度校验&#xff0c;请实现对密码的校验&#xff0c;要求满足&#xff1a; 包含大…...

Chocolatey

Chocolatey Software | PHP (Hypertext Preprocessor) 8.3.1 msi安装包https://github.com/chocolatey/choco/releases/download/2.2.2/chocolatey-2.2.2.0.msi 设置/安装 巧克力味Chocolatey CLI &#xff08;choco&#xff09;设置/安装 要求 受支持的 Windows 版本Windows …...

雍禾植发成毛发行业标杆!雍禾医疗获“年度医疗大健康消费企业”

近期&#xff0c;以“新视野 新链接”为主题的2023 EDGE AWARDS全球创新评选榜单正式发布。该评选由钛媒体发起&#xff0c;聚焦大健康产业&#xff0c;由权威行业专家、王牌分析师、专业投资机构、用户代表共同评审&#xff0c;兼顾综合专业性、影响力、创新性三大维度评选而出…...

Linux内核--进程管理(十二)共享内存和信号量

目录 一、引言 二、基础知识 三、统一封装的接口 ------>3.1、kern_ipc_perm 四、共享内存的创建和映射 ------>4.1、创建共享内存 ------>4.2、共享内存的映射 五、信号量的创建和使用 ------>5.1、信号量的创建 ------>5.2、信号量的初始化 ------…...

java 构造方法

构造方法 1、什么是构造方法&#xff0c;有什么用&#xff1f; 构造方法是一个比较特殊的方法&#xff0c;通过构造方法可以完成对象的创建&#xff0c;以及实例变量的初始化。 换句话说&#xff1a;构造方法是用来创建对象&#xff0c;并且同时给对象的属性赋值。 注意&#x…...

CISSP 第2章: 人员安全和风险管理概念

第二章 人员安全和风险管理概念 2.1 促进人员安全策略 构建工作描述方面的重要因素包括: 职责分离: 把关键的、重要的和敏感工作任务分配给若干不同的管理员或高级执行者&#xff0c;防止共谋 工作职责:最小特权原则 岗位轮换:提供知识冗余&#xff0c;减少伪造、数据更改、偷…...

前端八股文(CSS篇)一

目录 1.px和em的区别 2.介绍下BFC及其应用 3.介绍下粘性布局&#xff08;sticky&#xff09; 4.清除浮动的方法 5.如何用css或js实现多行文本溢出省略效果&#xff0c;考虑兼容 6.如何触发重排和重绘&#xff1f; 7.重绘与重排的区别&#xff1f; 8.说说两种盒模型以及区…...

游戏加速器LSP/DLL导致WSL.EXE无法打开问题修复!

解决办法&#xff1a; https://github.com/microsoft/WSL/issues/4177#issuecomment-597736482 方法一&#xff1a;&#xff08;管理员身份&#xff09; netsh winsock reset 方法二&#xff1a; WSCSetApplicationCategory 函数设置LSP加载权限 bool NoLsp(const wchar_t* …...

宏电股份5G RedCap终端产品助力深圳极速先锋城市建设

12月26日&#xff0c;“全城全网&#xff0c;先锋物联”深圳移动5G-A RedCap助力深圳极速先锋城市创新发布会举行&#xff0c;宏电股份携一系列5G RedCap终端产品应邀参与创新发布会&#xff0c;来自全国5G生态圈的各界嘉宾、专家学者济济一堂&#xff0c;共探信息化数字化创新…...

网站统计代码添加/专业seo培训学校

[oracle] to_date() 与 to_char() 日期和字符串转换 to_date("要转换的字符串","转换的格式") 两个参数的格式必须匹配&#xff0c;否则会报错。 即按照第二个参数的格式解释第一个参数。 to_char(日期,"转换格式" ) 即把给定的日期按照“转换…...

wordpress增加404/seo专业培训课程

12月12日&#xff0c;腾讯START云游戏TV版正式上线&#xff01;无需游戏主机&#xff0c;通过连接游戏手柄用户就能在获得START认证的智能电视上畅玩游戏库内的精品游戏。START还将视野拓展至游戏开发者&#xff0c;乃至手柄外设、路由器、运营商等一整条行业生态链&#xff0c…...

学校网站开发/网址和网站的区别

误解一&#xff1a;数据仓库和数据湖二者在架构上只能二选一 很多人认为数据仓库和数据湖在架构上只能二选一&#xff0c;其实这种理解是错误的。数据湖和数据仓库并不是对立关系&#xff0c;相反它们的并存可以互补给企业架构带来更多的好处&#xff1a; 数据仓库存储结构化的…...

静态页优秀网站/seo排名赚钱

《C4D的十万个为什么》首发于 公众号&#xff1a;苦七君 免费搜索查看更多问题&#xff1a;kuqijun.com 问题&#xff1a; C4D不能加载object文件&#xff0c;obj文件&#xff1f;提示未知文件格式 答案&#xff1a; 要显示文件名后缀看一下&#xff0c;有时候在文件类型里面…...

企业建站公司案例/人工智能培训课程

一、 直接插入排序思想&#xff1a; 将待排序的记录Ri&#xff0c;插入到已排好序的记录表R1, R2 ,…., Ri-1中&#xff0c;得到一个新的、记录数增加1的有序表。 直到所有的记录都插入完为止。 设待排序的记录顺序存放在数组R[1…n]中&#xff0c;在排序的某一时刻&#xff…...

godaddy如何创建网站/最大免费广告发布平台

选课系统6. 创建数据库创建数据库设置编码为UTF8CREATE DATABASE choose CHARSET utf8;6.1 创建班级表表名:classes字段:class_no 整型 自增长 主键 -- 班级编号class_name char(20) 非空 唯一 -- 班级名称department_name char(20) 非空 -- 院系名称create tableclasses(cl…...