内存,大家最熟悉不过的一块内容,也可能最不了解的一块内容,熟悉是因为听到这个词的频率非常高,【啊,我内存不够了,手机好卡啊】这是我听到过最多的吐槽,不熟悉是,内存怎么工作,内存的数据交换过程中都谁参与了,内存对于设备来说,如果出现极端场景的话,设备会有什么影响?等等..等等..一堆的问题都好像跟内存相关,今天就按照测试向去理解探讨下内存在客户端性能中的一面。
1、内存的科学解释(摘百度)哈哈;
2、内存在性能测试中的表现形式;
3、内存的类型以及含义;
4、内存的特殊表现有哪些?
5、内存数据在版本迭代过程中扮演的角色以及重要性;
内存 (Memory) 是计算机的重要部件之一,也称内存储器和主存储器,它用于暂时存放 CPU 中的运算数据,与硬盘等外部存储器交换的数据。它是外存与 CPU 进行沟通的桥梁,计算机中所有程序的运行都在内存中进行,内存性能的强弱影响计算机整体发挥的水平。只要计算机开始运行,操作系统就会把需要运算的数据从内存调到 CPU 中进行运算,当运算完成,CPU 将结果传送出来。
首当其冲,内存泄漏问题可谓是听的最多,导致移动端崩溃闪退的情况最多的元凶之一,内存泄漏问题上,初步接触性能测试的人员一直存在一个误区,那就是在测试过程中,内存一直处于上升状态是不是就是发生了内存泄漏问题?答案是否定的,我们先来看看游戏客户端性能的过程中发生内存泄漏时,如何正确判断发生了泄漏。
解释下正常泄漏时的原因
图中可以看出在特定的某个场景,内存申请是相对固定的情况,却每次使用该场景时引用的资源脚本,有固定的几个内存对象遗漏,随着使用该场景次数的增加,内存的值会有轻微/严重的增长,并且不会被清除,这部分内存就是泄漏造成的。图中的 5MB 就是泄漏的内存。
泄漏时测试的执行手段以及常用场景
举个栗子,副本泄漏测试,可以发现每次从副本返回之后内存的基准值在不断的上升,这就意味着副本中有资源/代码堆未卸载干净,有泄漏,这样的话,副本的泄漏测试问题就定位出来,而具体的内存泄漏是什么?见下一章
延伸:副本泄漏测试如此,举一反三,其他的泄漏问题同样适用,如:UI 泄漏测试,频繁打开关闭 UI 跳转界面,查看表现,跑马灯测试,频繁的唤起跑马灯内容,查看内存变化,都是可以的。
内存基数过高就很简单了,是针对于内存分配极度不合理的情概况去看的。
举个栗子,查看下图,我们发现在登录界面时,内存就已经飙升到 500MB,而进入核心的场景后才 650MB,严重说明,登录阶段存在严重的内存分配不合理的情况。需要优化,后续需要针对性的把资源占用较大的内容优化或者删除。
内存峰值也相对简单,但是又属于比较重要的部分,因为它是评估项目在设备上是否存在崩溃风险的一个指标。
举个栗子,我们来看一下,每个项目我们在跑完核心流程的过程中,内存值都会存在一个最大值,这个值就是内存峰值,内存峰值的出现意味着项目可能达到的一个极限值,上回我们也说到,硬件决定项目的上限,如果内存过高超过上限,设备就会干掉项目,峰值的意义就是如此。
延伸:比如 iOS 设备就是 1G 运存机型,645~649MB 就会杀掉进程,2G 运存机型,1400MB 就会杀掉进程。Android 设备也存在类似的现象,但是现在机型都解禁,底层内存不足会优先杀掉未使用队列进程,涉及底层调度问题后续介绍。
顾名思义,就是这部分的内存是多余的,而且它大多会响应在开发中最常用的池应用,以及需求变动的过程中。内存冗余就相对复杂一些,理解会好理解,定位会麻烦且复杂一些,具体定位方式放后篇。
VSS : Virtual Set Size 虚拟耗用内存(包含共享库占用的内存)
RSS : Resident Set Size 实际使用物理内存(包含共享库占用的内存)
PSS : Proportional Set Size 实际使用的物理内存(比例分配共享库占用的内存)
USS : Unique Set Size 进程独自占用的物理内存(不包含共享库占用的内存)
常用的就只有 VSS 与 PSS 两个,虚拟内存在测试过程中用来判断申请内存时的一个内存状态,PSS 则是真实运行项目时,真实所占用的项目资源 + 项目代码堆 + 三方库/系统库引用时占用部分的内存是最真实反应。前者因为虚拟基址 Google 官方有限制为 0~4G 避免出现杀进程的情况,后者则就是我们最常看的内存值。
介绍 PSS 内存中不同类型
我们知道 Perfdog 中 memory detail 栏内存类型取自 adb meminfo 的内存类型,但是取值上会有些差别,后期感兴趣的可以给各位留个作业,看一下,内存类型不同在哪里?取值有差异时是什么原因?
Perfdog memory detail 如下图展示
adb dumpsys meminfo {}获取指标如下展示
上图中我们发现,meminfo 的内存类型很多,Perfdog 取内存类型时,并没有全部都取,而是取到了一部分,而这部分基本就够用了,也跟 TX 本身游戏项目多用于 Unity 引擎有一定的关系。因此我们只需要理解其中一部分大头内存类型即可,足以快速定位到很多内存问题。
特殊提醒:感兴趣的可以延伸的去里了解 meminfo 中的内存类型都是什么意思,这个不多赘述了。
从上图中可以看出内存的类型常用并且要观察的就是:
NativePss:项目中常驻内存,包含的就是常用资源文件,库文件,以及脚本文件;
Gfx/GL:反映的基本上就是渲染底层驱动给到的内存,我这里一般就认为是"显存",他们具体的区别这里我也没有深究,只知道不同的设备取值时,时而是 Gfx,时而是 GL,因此我猜测都是显存理解,如果有出入,欢迎交流;
unknow:在 Unity 项目中一般就理解为 Mono 堆,其他项目未延伸去理解,感兴趣的依然可以去拓展延伸的了解。
内存压缩
内存值中存在内存交换区域,名为 swap,用来压缩缓存,保留不常用/通用内存,它属于底层调度的一部分,也是真实反应在 PSS 内存中的,因此真实的内存计算规则是:内存 memory+ 交换内存 swap memory,如果一旦 swap memory 升高意味着有部分内存在后台做压缩处理,而压缩的操作是由 CPU 来参与的,无疑加重了 CPU 的开销,中低端机上就会表现出机身发热,卡顿的情况,后篇着重介绍。
显存升高
显存升高直接反应的情况也是底层硬件调度机制有关,我们目前只需要知道显存是用来保留渲染数据产生的内存做缓冲去做预留,如果它升高意味着在传输 I/O 阶段存在瓶颈,需要优化渲染流程,后篇会着重解释。
扮演角色
主角,妥妥的主角,它的影响关乎项目的生死,也是项目中重点关注的指标之一,上述的内存情况都要一一考虑去评估,反应在每次版本迭代中。
迭代应用
同上篇的流畅度一致,可以在迭代过程中作为评估优化效果,竞品分析等的一项衡量指标去做记录。
综上所述
1、内存分多种类型,主要关注 PSS;
2、内存在不同表现下,场景不同,评估方式也不同;
3、内存在客户端性能中地位很高,也是重点关注的对象,需要认真去看,着重去分析;
4、内存涉及部分 I/O 阻塞,其他硬件方便的内容;
另外欢迎各位大佬进群沟通哈!~