目录
1、关于”内存”
2、APP使用内存及衡量指标
3、常见的内存问题及可能的原因
4、结合腾讯课堂浅谈内存测试方法
一、关于“内存”
首先我们所说的“内存”是指终端系统运行内存,用于暂时存放CPU中的运算数据,与外部存储进行交换的数据。从启动终端APP的那一刻起,内存就伴随着app的整个生命周期,我们的每一次点击、刷新、进出页面等等操作都会产生内存的使用、释放和消耗。终端的运行内存大小是固定的,如果APP一次性使用大量内存或者持续占用内存而不释放,那么对APP的正常使用势必会造成直接或潜在的影响。这里我们引入两个名词,性能瓶颈和内存泄漏。性能瓶颈:限制系统性能的关键因素。可以类比木桶的短板来理解这个瓶颈。内存泄漏:通俗来讲就是系统分配的内存被持续占有而没有归还给系统,详解请参见第三节。那么我们可以从这两个角度来分析内存对APP性能的影响。
二、APP使用内存及衡量指标
1、内存用在了那里?
把app的生命周期以进程单位来看的话,使用内存的为以下四种途径:
(1)自身代码使用的内存
(2)共享库代码使用的内存
(3)运行过程中分配的堆和栈使用的内存
(4)通过map映射的磁盘文件内容使用的内存
2、衡量内存占用的指标
根据在进程中内存的使用和分配方式,我们将内存分为四种类型:
VSS- Virtual Set Size 虚拟耗用内存
RSS- Resident Set Size 实际使用物理内存
PSS- Proportional Set Size 实际使用的物理内存
USS- Unique Set Size 进程独自占用的物理内存
(1)VSS
首先我们解释一下虚拟内存和物理内存的联系与区别。虚拟内存和物理内存之间是存在着映射关系的,进程直接操作的内存是虚拟内存,而代码和数据是放在物理内存中的。当进程向系统申请内存时得到的是虚拟内存,如果进程后续没有使用这些虚拟内存,那么它们也不会和物理内存关联起来,不会真实耗费物理内存。比如我们申请100M的虚拟内存,实际只用例1byte,那么耗用的物理内存就只有4096byte即一个内存页(关于内存分页的内容这里就不详细描述了。)。VSS-虚拟消耗内存指的是进程申请的虚拟内存大小,由以上可知进程实际使用的物理内存是小于等于虚拟内存大小的。属于一个理论值。我们举个例子说明一下。当用户在app内打开某个页面,会先申请一块虚拟内存以满足该页面可能发生的操作使用但是用户并没有在这个页面进行任何操作,那么实际使用的物理内存是小于虚拟耗用内存的,因此是不适用于作为衡量APP使用内存的指标的。
(2)RSS
上面我们说VSS是因为大于等于物理内存,那这个RSS代表的实际使用物理内存是不是就符合要求了呢?这里我们还需要知道一个概念,共享内存:顾名思义,共享内存就是各个进程之间可共同使用的一些诸如代码库、父子进程、进程自身的代码等等它们只会使用一次物理内存,但是在每个独立进程中都被认为是自己使用了这一部分的物理内存。似乎对于单个进程来说这是没有问题的,但是当进行多个操作,同时这些进程中有共享内存的时候就会在计算的时候重复加上这一部分的使用物理内存,最后也会导致衡量APP使用内存不准确。
(3)PSS
显然我们知道只要解决了共享内存的问题我们就可以得到准确的APP使用内存。这里采用的方法是将共享库的内存M按照使用的进程数n进行平分成n份,每个进程的PSS值中就有M\n大小的共享内存。这样就完美的解决了共享内存多次计算的问题。所以PSS值是我们计算APP使用内存的最佳标准
(4)USS
USS-进程独自占用的物理内存,一般这个数据没有太大的参考价值,所以不作为标准之一。
三、性能相关的内存问题及可能的原因
内存相关问题有很多,诸如内存泄漏、内存溢出、野指针、空指针、内存越界访问、引用未初始化的变量等等。但是我们APP性能相关的我们只关注内存泄漏和内存溢出。
1、什么是内存泄漏和内存溢出
举个例子,你一共有四个盒子一个小球每个盒子都有一把锁,小球放在第一个盒子里,你打开第一个盒子拿出小球,再锁上,这时候你发现你丢了第一个盒子的钥匙可是你需要一个盒子装小球,所以你使用了第二个盒子,如同第一步一样再拿出再丢钥匙再使用盒子,直到四个盒子都使用完小球也无处可放。对比这个例子中的拿出小球丢了钥匙再想放小球就需要新的盒子,就是我们进程申请内存之后没有释放再次打开进程就需要申请新的内存,这就是内存泄漏。当四个盒子都被锁上,小球无处安放的时候就相当于进出持续申请内存至内存被使用完全或者达到阈值,再次申请无内存可用了的时候这就是内存溢出。
由上可知内存溢出是内存泄漏持续累积的结果,最终导致的现象是系统报错OOM。
2、内存泄漏的分类
根据内存泄漏发生的场景对内存泄漏进行分类可为:常发性内存泄漏、偶发性内存泄漏、一次性内存泄漏、隐形内存泄漏
(1)常发性内存泄漏是指发生泄漏的代码只要被执行到就一定会导致一次内存泄漏的场景。这种内存泄漏是我们主要关注的也是最严重的内存泄漏。
(2)偶发性内存泄漏是指发生泄漏的代码只在特定的环境或者操作下才会发生,并非每次执行到该代码都会造成内存泄漏的场景。
(3)一次性内存泄漏是指发生泄漏的代码只会执行一次,导致有且只有一次泄漏的发生。例如一些数据缓存行为、模型或三方库的内存占用等。这种场景不易察觉且影响较小。
(4)隐形内存泄漏是指程序在运行过程中持续的分配内存却没有释放操作,直到运行结束才统一释放的现象。本质上这种不算内存泄漏,但是这种行为对系统的压力较大,是不可取的。且这种开发方式出现的概率应该极低。
3、可能造成内存泄漏的原因
(1)内存没有回收
内存没有回收是最明显却又最常见的问题,属于不按照代码规范造成的泄漏。
(2)activity泄漏
该种泄漏常见于静态activity,在activity的生命周期中如果不清楚对它的引用,那么这个类对象就会常驻在内存中,即不会释放使用的内存。
(3)单例模式
单例模式属于设计模式中较简单的一种,其保证了一个类只会创建单个对象,该模式的静态特性使得其生命周期和应用的生命周期是一样长的,当这个对象加载了一些资源或数据,或这个对应强引用了其他的对象而被引用的对象加载了一些资源,那么这些资源将跟随该单例对象的生命周期,那么就会出现内存泄漏。
(4)加载的数据量过大,一次性从数据库中取出过量的数据
(5)代码中存在死循环或者循环产生过多重复的对象实体
(6)异步操作未设置超时机制
因为异步操作会涉及网络资源和内存资源的分配,若出现服务器异常持续等待,客户端频繁发起异步请求,就会持续消耗网络资源和内存资源,造成内存泄漏。
(7)快速连续操作导致状态不一致
简单来说就是快速重复的点击等操作同一个功能可能会造成功能状态混乱导致资源未能成功回收导致内存泄漏,更详细的俺也没搞明白。
四、结合腾讯课堂浅谈内存测试方法
1、内存测试三种状态
一般来说APP在可以在三种状态下进行内存测试:
(1)空闲状态下,该状态app一般处于后台或静置状态,app内存应处于不增不减的状态
(2)正常状态,正常使用app进行一些列操作时关注内存情况,这也是我们主要测试状态
(3)高强度状态,该状态一般使用monkey来持续不断的操作app,通过是否有OOM来简单判断是否存在内存泄漏直至溢出
2、腾讯课堂测试场景
腾讯课堂是一款提供直播录播学习平台的软件,除了代码层面我们不可知的一些内存问题外,测试角度我们可以侧重的关注点有以下这些:
(1)APP处于后台或者静置状态时内存应该处于不增不减的状态
(2)基本的功能页面点击刷新操作,这些操作是每一款软件都需要测试到地方,确保在正常功能按钮点击和页面进入及刷新不会引起内存激增。
(3)页面持续加载操作,页面的持续加载其实也就是数据的不断加载过程,我们需要关注在不断的加载过程中内存数据是否呈现有升有降的曲线,且总体趋势保持平稳。
(4)打开多个不同的页面或进行页面之间的跳转,每打开一个页面都会消耗一些内存,当从一个页面去到另一个页面的时候前一个页面理应是被干掉或压栈处理的,那所申请的内存资源应该全部或大部分释放掉,若在这个过程中内存增长较快且静置一段时间后没有明显下降,我们可以认为存在内存泄漏。
(5)频繁进出同一个页面或同一类页面,课堂常见的内存泄漏问题就出在频繁进出课详页。因为进入课详页可能包括了视频资源的预加载和渲染、大量图文消息的加载和渲染、目录资源的加载等等,那么在处理这些资源的时候就可能存在未释放或者释放不完全的现象。
(6)课详页或任务页切换多次切换正在播放的视频,按照录播播放的正常逻辑,视频是一边加载一边播放一边释放的过程,保留的仅仅是视频的第一帧资源以便下次进入的时候好快速展示。那么视频播放和切换的过程理论上内存的增长曲线应较为平缓,有升有降,峰值和低值相差不大,静置后内存有明显回落。
(7)短视频频繁切换和快速滑动,和录播课测试类似,短视频场景下的内存曲线应该是与录播课相似的。
(8)直播间老师频繁发起举手、签到、上下台等各种push,学生端频繁进房和举手上台、签到、参与抽奖等等活动,同时关注长时间直播下是否会发生crash,因为直播间是一个持续渲染视频画面的过程,根据不同的直播框架对渲染数据的处理方式不同。如opensdk需要将渲染数据拷贝一份再进行渲染,这个过程是需要暂时使用内存,如果这个时候发生进程等待和后续渲染数据的持续传入,那就有概率发生内存耗尽主线程卡死的问题。
(9)串联应用核心流程走一遍,观察内存曲线是否正常。
注:以上测试过程需要注意控制变量,即每一个场景的测试都在相同的初始条件下,多次测试取平均值时每个场景测试相同的时间进行相同的操作,每个场景完成后静置等待观察内存曲线回落情况。
3、测试工具
腾讯课堂测试过程中我们有两种测试内存的工具
(1)perfdog
使用perfdog连接测试机器可以直观看到内存曲线和数据,具体使用说明参见:https://bbs.perfdog.qq.com/article-detail.html?id=5这里我们只关注Memory这条曲线就好。
(2)adb
使用adb命令:adb shell dumpsys meminfo com.tencent.edu可以直接查看腾讯课堂内存情况,其中我们关注PSS值即可