小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
本文已参与 「掘力星计划」 ,赢取创作大礼包,挑战创作激励金。
为什么关注性能
当我们使用移动端使用APP很开心时,突然APP怎么点都没有反应,我们内心那种焦灼感,都要提到嗓子上了~,相信大多数人都会遇到这样的场景吧
通常,用户评价一个APP的好坏,往往不仅关注APP的基本功能的正常,还要关注 APP 大小、运行速度、卡不卡等性能上的表现
因此,用户关注的点,也是我们在前期测试APP时重点关注的
所以为什么关注性能?
- 用户体验:用户体验APP运行快不快、流不流畅
- 性能稳定:APP在不同平台上,稳定运行,无崩溃现象
- 产品竞争力:同样环境下,性能调优,有助于产品在市场上的竞争
因此,本期我们将学习Android性能测试中场见的指标,Let's go~
1. 性能测试概述
性能测试是压力测试其中之一,目的是验证 APP 在负载条件下,检测APP稳定性、响应性等指标数据的表现,且在过程中发现消除APP性能缺陷。
APP 性能测试目前行业中常见的指标汇总如下:
2. 内存指标概念
APP 会依赖设备中的内存,但设备中的内存总大小有限。
同时设备对应单个应用的内存使用也是有限的。
因此,内存管理是对于一个APP来说是至关重要的
-
内存指标 全称 含义 等价 USS Unique set Size 物理内存 进程独占的内存 PSS Proportional Set Size 物理内存 PSS= USS+ 按比例包含共享库 RSS Resident Set Size 物理内存 RSS= USS+ 包含共享库 VSS Virtual Set Size 虚拟内存 VSS= RSS+ 未分配实际物理内存
1. 内存的大小关系* :VSS >= RSS >= PSS >= USS
2. 查看APP内存大小时,我们实际看的就是应用的PSS值
- 内存查看方法
adb shell dumpsys meminfo 应用包名
也可以使用 procrank
adb shell procrank | grep packagename
3. 内存限制
内存属性 | 说明 |
---|---|
dalvik.vm.heapstartsize=8m | 应用启动后, 系统分配给它的Heap初始大小. 随着应用使用可增加 |
dalvik.vm.heapgrowthlimit=192m | 默认情况下,应用可使用的Heap的最大值, 超过这个值就会产生OOM |
dalvik.vm.heapsize=512m | 如果应用的manifest文件中配置了largeHeap属性,则App可使用的Heap的最大值为此项设定值 |
dalvik.vm.heapminfree=2M | 单次Heap内存调整的最小值 |
dalvik.vm.heapmaxfree=8M | 单次Heap内存调整的最大值 |
dalvik.vm.heaptargetutilization=0.75 | 当前理想的堆内存利用率。 GC后, Dalvik的Heap内存会进行相应的调整, 调整到当前存活的对象的大小和 / Heap大小 接近这个选项的值, 即这里的0.75 只是一个参考值 |
我们可以通过 adb shell getprop | get dalvik.vm.heap
查看内存情况
- Android对每个App设置了堆大小限制,可以在系统里配置,但APP无法控制
- 如果App运行过程中占用的内存超出限制的 App 堆大小,就会收到 OutOfMemoryError
4. 内存回收
内存回收全称Android 垃圾回收机制,简称GC。指的是Android 对无用对象进行清理,以释放内存供其他应用使用
单个的GC并不会占用太多的时间,但是大量的GC操作则会显著,占用帧间隔时间(16ms)
-
GC 触发条件
-
当一个进程死亡时
-
当启动指定的Activity失败时
-
在更新进程adj值时
-
处理完当前所有广播时
-
-
GC内存回收规则:
- 根据进程优先,优先杀优先级低的
- 进程优先级一样的应用,优先杀内存占用更大的
-
查看方法
可以使用adb logcat | grep <pid>
5. 内存场景问题
-
内存抖动
- 严重级别:C或D,问题选解,影响有限,故无强制要求
- 产生的原因:大量的对象在短时间内创建和释放,频繁触发GC造成UI卡顿
-
内存泄漏
- 严重级别:B或C,问题选解,高概率必解
- 产生的原因:由于疏忽或错误导致程序未能释放已经不再使用的对象
- 影响:发生内存泄漏会导致内存中的剩余可用Heap Size越来越小,这样会导致频繁触发GC,更进一步引起性能问题,比如最终导致内存溢出
-
内存溢出
- 简称:OOM
- 严重级别: A或B,问题必解
- 产生的原因:超过设备对应用的堆内存限制
-
内存溢出的场景有:
- 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
- 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
- 代码中存在死循环或循环产生过多重复的对象实体;
- 使用的第三方软件中的BUG;
- 启动参数内存值设定的过小
-
内存溢出的解决方案:
第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
第二步,检查错误日志,查看“OutOfMemory”错误前是否有其 它异常或错误。
第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。 重点排查以下几点: 1.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
2.检查代码中是否有死循环或递归调用。
3.检查是否有大循环重复产生新对象实体。
4.检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
5.检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
第四步,使用内存查看工具动态查看内存使用情况
6. 性能优化
-
Bitmap优化:
- 按需显示:BitmapFactory.Options设置inSampleSize
- 及时回收
- 使用图片缓存(LruCache、DiskLruCache)
-
代码优化:
- 避免在循环体中new对象,复用对象
- 防止Activity/Fragment泄漏
- 及时关闭资源(文件、数据库等)
- 线程管理:使用线程池、及时停止线程
总结
本期,主要学习了Android APP性能测试指标的内存相关概念及出现的场景的学习
以上是本期内容,欢迎大佬们点赞评论,下期见~