移动APP性能评测与优化
本文是《移动App性能评测与优化》的读书笔记。
PS:说是读书笔记,其实就是摘录。
移动App的性能测试主要包括:内存使用情况、电量消耗、功能的流畅度等;
1. 内存
1.1 内存的主要组成索引:
Native Heap : Native 代码分配的内存,虚拟机和Android框架本身也会分配;
Dalvik Heap : Java 代码分配的对象;
Dalvik Other : 类的数据结构和索引;
so mmap : Native 代码和常量;
dex mmap :Java 代码和常量;
1.2 内存测试工具
Android Studio / Memory Monitor : 观察 Dalvik 内存;
dumpsys meminfo : 观察整体内存;
smaps : 观察整体内存的详细组成;
MAT : 详细分析 Dalvik内存;
1.3 一个类的内存消耗
虚拟机在创建对象时的操作:
loadClass,将类信息从 dex 文件中加载进内存:
读取 .dexx mmap 中 class 对应的数据;
分配 native-heap 和 dalvik-heap 内存创建 class 对象;
分配 dalvik-LinearAlloc 存放 class 数据;
分配 delvik-aux-structure 存放 class 数据;
new instance 操作,创建对象实例
执行 .dex mmap 中 和 的代码;
分配 delvik-heap 创建 class对象实例;
dex mmap
在Android应用中的作用是映射classes.dex文件
1.4 dex 优化
省略掉dex的文件结构(自行查阅)
为了节省空间,dex将原先在 class 文件中重复的信息集中放置在一起,并以索引和指针的形式支持快速访问。
dex 文件中数据基本是按类名的字母顺序进行排列的,这样同样包名的类会排在一起,但程序实际执行时,同一个包下的类并不会全部调用到,而是跨包进行交互,但 mmap 加载了整个页面,可能会有很多无用的数据。
优化;
在APK的编译流程中,Proguard 混淆工具正好是能够对类名进行修改的,可以根据程序运行时的逻辑,将那些会互相调用的类改为为同一个 package 名,这样就可以使它们的数据排布在一起。
1.5 MAT(Memory Analyzer Tool)
使用MAT来分析应用的内存使用情况。通常在使用MAT打开hprof
文件后,能够在首页看到Top Comnsumers和 component Report等功能,我们可以快速定位一些大块的内存消耗。但我们在分析时会发现系统资源类占据了很大一部分内存,因此为去除这部分对分析的干扰,我们在使用AndroidSDK
提供的hprof-conv
转换时需要增加一个参数:
hporf- conv [-z] <infile><outfile> -z:exclude non-app heaps,such as Zygote
如果hprof文件是已经转换过的,则可以使用OQL:
//在数据中寻找应用的Application类对象,将对象地址转换为十进制后输入以下查询语句:
select * from instanceof java.langObject s where s.@objectAddress> 1107296256
//(后面那串数字应该是Application类对象的地址)
采用这两种方法后,再使用MAT来分析就可以比较容易发现自身代码的内存问题。
1.6 测试经验
MAT 是探索 Java 堆并发现问题和好帮手,能够迅速发现常见的图片和大数组等问题;
内存碎片问题一般隐藏在对象的地址中;
如需要测试非 Dalvik部分,有必要了解 Linux 的进程和内存原理、内存共享机制,熟悉常用命令行工具;
内存分配的最小单位是页面,通常为4KB,这个限制会引发各种问题;
1.7 性能优化
尽量不要在循环中创建很多临时变量;
可以将大型的循环拆散、分段或者按需执行;
引入SDK库和调用新的系统API里需要考虑成本;
除了Dalvik堆内存,还有其他类型的内存在了解了原理后也能够进行分析和优化;
dex 文件有很多优化空间。在仔细统计并调整了dex文件的顺序后,往往可以节约1M以上的 mmap 内存;
2. 耗电
在保证用户的必要体验前提下,尽可能减少不必要的操作。几个优化方法:
方法一:CPU时间片
当应用退到后台运行时,尽量减少应用的主动运行,当检测到CPU时间片消耗异常时,深入线程进行分析;
使用 DDMS 的 traceview 工具:获取进程运行过程中的 traceview,定位CPU占用率异常的方法。
方法二 wake lock
前台运行时运不要去注册 wake lock。 此时注册没有任何意义,却会被计算到应用电量消耗中。后台运行时,在保证业务需要的前提下,应尽量减少注册 wake lock;降低对系统的唤醒频率,使用 partial wake lock 代替 wake lock;
方法三 传感器
合理地设置 GPS 的使用时长和使用频率;
方法四 云省电策略
可考虑定期上报用户手机电量数据的方式来分析问题;
3. 流畅度
3.1 分析工具
hierarchy Viewer ,帮助我们去分析UI布局的情况;
Tracer for OpenGL ES,可以记录和分析APP每一帧的绘制过程,以及列出所有乃至的OpenGL ES 的绘制函数和耗时;该工具操作后会生成一份记录App绘制过程和gltrace文件,
Lint 扫描,发现代码中的流畅度性能问题;
Traceview,跟踪程序性能,具体到每一个函数的耗时和调用次数
Systrace ,获取App运行时线程的信息以及Api执行情况
< merge > 标签:用于减少View树的层次来优化 Android 的布局,通过该标签可以把 < merge > 标签里的UI合到上一层的 layout中。
< ViewStub> 标签,最大的优点是当你需要时才会加载,使用它并不会影响UI初始化时的性能。各种不常用的布局可以使用该标签来减少内存使用量,加快渲染速度。< ViewStub> 是一个不可见的,大小为0的View。
对于不常用的 UI 可以考虑使用 < ViewStub> 标签替代 GONE 来提高 UI 性能:
将 View 的可见性设置为 GONE,在 Inflate 布局时 View仍然会被 Inflate,也就是说仍然会创建对象,会被 实例化。而 ViewStud 是一个 轻量级的 View,它是一个看不见、不占布局位置、占用资源非常小的控件。
3.2 Perforjmance中的16个问题
DrawAllocation: 避免在绘制或者解析布局(draw/layout)时分配对象,比如在Ondraw()中实例化 Paint 对象;
Wakelock, 手机不能进入休眠状态,导致手机一直保持在高耗电状态;
Recycle :某些资源,比如 TypedArrays 、 VelocityTrackers,用完后应该被回收,但是忘记回收。
ObsoleteLayoutParam : Layout中无用的参数;
UseCompoundDrawables,可优化的布局;
HandlerLeak: Handler 的使用不当导致内存泄漏;
UseSparseArrays ,尽量用 Android 的SparseArray 代替 Hashmap;
UseValueOf : 需要常量对象时,不应该直接 new, 应该使用 ValueOf 转换。比如需要整数 42 的对象,不要直接用 new Integer(42),应该用 Intener.vallueOf(42),这样可以省内存;
DisableBaselineAlignment: 如果 LinearLayout 被用于嵌套 layout空间 计算,它的 android:baselineAligned 属性应该设置成 false ,以加速 layout 计算;
InefficientWeight : 当线性布局里只有一个控件,并且使用了weight 属性,最好把 weidth 和 height 设置为0,这样可以省略布局的 measure 过程;
FloatMath, 使用 FloatMath 代替 Math;
NestedWeights : 避免嵌套 weight ,那将拖累执行效率。
UnusedResources / UnusedIds, 未被使用的资源会使程序变大,并且编译速度降低;
Overdraw: 如果为 RootView 指定一个背景 Drawable,会先用Theme 的背景绘制一遍,然后才用指定的背景,这就是所谓的 “Overdraw” ,可以设置 theme 的background 为 null 来避免;
UselessLeaf / UselessParent : View 或 view 的父亲没有用,应该把它移除,避免影响加深布局的层次;
UnusedNamespace : 有些代码没必要使用 namespace ,会影响代码执行效率;
4. 网络优化
考虑点:
分小片传输一个文件(图片),这样当某一个分片失败时,只需要重传这一个分片就可以,而不用重传整个文件;
不同类型的移动互联网下的分片初始大小应该有所不同;
在上传一个文件的过程中,应当尽可能动态增大分片大小,以减小分片数量;
确定每个分片是否要继续增大之前,要检查网络类型是否发生了改变;
分片一旦传输失败,应当使用该网络下的初始分片大小进行重试;
重点优化优质网络下的传输速度,而不特意优化差网络下的速度;
5. apk瘦身
5.1 瘦身关键点:
代码部分:冗余代码、无用功能、代码混淆、方法数缩减;
资源部分:冗余资源、资源混淆、图片处理(压缩、图片转换、点9图化等);
对整个安装包做7zip极限压缩;
Android 系统安装一个应用的过程中,其中有一步是对 Dex 进行优化,优化的过程是使用专门的工具 DexOpt。DexOpt 是在第一次加载Dex文件的时候执行的。在DexOpt的过程会生成一个ODEX文件。
早期的 DexOpt 有两个问题:
DexOpt 会把每一个类的方法的id 检索起来,存在一个链表的结构里的,但是这个链表的长度是用一个 short 类型来保存的,导致了方法 id 的数目不能超过 65536(2^16);
DexOpt 使用 LinearAlloc 来存储应用的方法信息,LinearAlloc是一个固定大小的缓冲区(4,5,8,16),当方法数量过多也会导致超出缓冲区大小时,也会造成 DexOpt 崩溃;
5.2 缩减方法数的方法
避免在内部类中访问外部类的私有方法或变量;当在 java 内部类(包括 匿名内部类)中访问 外部类的私有方法或变量时,编译器会生成额外的方法;
避免调用派生类中的未被覆盖( override) 的方法;避免在派生类中调用未覆盖的基类的方法;避免用派生为对象调用派生类中未被覆盖的基类的方法。因为当调用派生类中的未被覆盖的方法时,会多产生一个方法数;
去掉部分类的get 、set 方法;
5.3 代码混淆
代码混淆( Obfuscated code)也叫花指令;对代码进行 Proguard 后,也可以比较大的减小代码的体积(即 dex 的体积);
6 参考文献:
移动APP性能评测与优化的更多相关文章
- 《移动App性能评测与优化》读书笔记
第一章:内存 内存的主要组成索引: Native Heap:Native代码分配的内存,虚拟机和Android框架本身也会分配 Dalvik Heap:Java代码分配的对象 Dalvik Oth ...
- 移动App性能评测与优化-Android内存测试 ,DVM原理
常见的测试方法包括Monkey/UIAutomator类的常规压力测试,大数据/操作的峰值压力测试,长时间运行的稳定性测试等. 前提: 测试准备:版本是纯净版本,不应该附加多余的log和调试用组件. ...
- Android App性能评测分析-流畅度篇
1.前言 在手机App竞争越来越激烈的今天,Android App的各项性能特别是流畅度不如IOS,安卓基于java虚拟机运行,触控响应的延迟和卡顿比IOS系统严重得多.一些下拉上滑.双指缩放快速打字 ...
- Android App 性能评测与调优
要点: 1. 内存优化的目的以及工具介绍 2. Android APP 内存的主要问题分析与总结 3. UI 绘制原理以及量化工具 - UI 流畅度的主要问题分析以及 UI 绘制原理. 4. 如何获取 ...
- 移动App性能测评与优化1.4.4 多进程应用
1.4.4 多进程应用 根据上一节中的描述,当一个进程结束后,它所占用的共享库内存将会被其他仍然使用该共享库的进程所分担,共享库消耗的物理内存并不会减少.实际上,对于所有共享使用了这个库的应用,Pss ...
- Android APP性能分析方法及工具
近期读到<Speed up your app>一文.这是一篇关于Android APP性能分析.优化的文章.在这篇文章中,作者介绍他的APP分析优化规则.使用的工具和方法.我觉得值得大家借 ...
- android app性能优化大汇总(UI渲染性能优化)
UI性能测试 性能优化都需要有一个目标,UI的性能优化也是一样.你可能会觉得“我的app加载很快”很重要,但我们还需要了解终端用户的期望,是否可以去量化这些期望呢?我们可以从人机交互心理学的角度来考虑 ...
- fir.im Weekly - 如何进行 Android App 性能优化
关于 Android App 的优化,@anly-jun 用 3 个月完成了这一系列文章,从 性能分析工具 到 ANR .Layout .消除卡顿 到 内存优化.内存分析工具大概十五六篇,并对此做一个 ...
- iOS app性能优化的那些事
iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功能上面,比较少去考虑性能的问题,可能这其中涉及到objective-c,c++跟lua,优化起来相对 ...
随机推荐
- C#LeetCode刷题之#383-赎金信(Ransom Note)
问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3937 访问. 给定一个赎金信 (ransom) 字符串和一个杂志 ...
- Flutter 容器 (2) - Padding
Padding: 内边距Widget,与CSS中的padding相似. import 'package:flutter/material.dart'; class AuthList extends S ...
- MyBatis使用LocalDateTime遇到的一系列问题
问题 在Mybaits中传入参数为LocalDateTime,查询发现结果集为空,插入时发现时间相差13小时 测试 新建工程,新建测试库(主要此处新工程使用的JDBC为mysql-connector- ...
- Vue CLI3 移动端适配 【px2rem 或 postcss-plugin-px2rem】
Vue CLI3 移动端适配 [px2rem 或 postcss-plugin-px2rem] 今天,我们使用Vue CLI3 做一个移动端适配 . 前言 首先确定你的项目是Vue CLI3版本以上的 ...
- JVM的方法执行引擎-entry point栈帧
接着上一篇去讲,回到JavaCalls::call_helper()中: address entry_point = method->from_interpreted_entry(); entr ...
- 8.oracle 表查询
演示如何使用select语句,接下来对emp.dept.salgrade表结构进行解说. emp 雇员表 字段名称 数据类型 是否为空 备注 -------- ----------- -------- ...
- 超详细的阿里字节Spring面试技术点总结(建议收藏)
前言 Spring作为现在最流行Java开发技术,其内部源码设计非常优秀. Spring这个词对于Java开发者想必不会陌生,可能你每天都在使用Spring,享受着Spring生态提供的服务.现在很多 ...
- MySQL数据库修改字段名、字段类型、字段长度
1.MySQL数据库中,修改字段SQL如下: alter table AppVersion change version versionCode varchar() DEFAULT NULL COMM ...
- selenium定位方法(一)
selenium定位方法-(一) 1.定位页面元素的方式(By类的方法) 1)id定位:通过页面元素的id属性值来定位一个页面元素 注意事项:如果每次刷新网页之后元素的id属性值都不同,说 ...
- Qt 多语言转换
Qt QTranslator 实现多语言转换(转载) 1.在*.pro文件里面添加TRANSLATIONS += English.tsChinese.ts根据自己想要添加多少种语言和什么语言视情况 ...