快速定位手游内存占用过高问题

作者:Oliver,腾讯WeTest团队产品经理。

为了避免手机性能成为游戏选择时的壁垒,游戏厂商必须进行更好的游戏性能优化。本文利用WeTest平台的Cube工具,通过三步完成游戏内存检测与分析的过程,希望为游戏开发者提供一些内存优化的方法和思路。

众所周知,手游在2016年进入了成熟期,全球的开发商数量在减少,游戏增速也在放缓,更少的游戏意味着高质量的游戏将获得更多的传播和更久的生命力,质量的提升就会带来画面的美化、场景的丰富等,对手机性能也带来了更多的考验。为了避免手机性能成为游戏选择时的壁垒,游戏厂商必须进行更好的游戏性能优化。

那么,游戏性能是什么?游戏性能就是决定了游戏耐久度,承载能力和运行速度的因素。

简单来说,游戏性能决定了你的游戏能否跑的更稳,跑的更久,跑的更快。进入了手游精品时代之后,为什么不管什么游戏,言必谈手游性能?因为在PC时代,如果游戏性能优化一般,玩家加个内存换个CPU或者刷个主频就能轻松搞定;到了手游时代后情况则显得比较严峻,捉襟见肘的内存使得资源加载时如履薄冰,加上高中低不同配置的机型让性能问题显得更加突出,对于玩家来说,为了一款游戏而更换手机的可能并不大,一个低端机型上的卡顿就可能造成一大批用户的流失,如果手游性能表现糟糕,再好的游戏设计都会付诸东流。

那么什么样的手游才是更稳,更久,更快的呢?

我们一般看这样几个指标:

对于手游来说,这些指标的情况就决定了游戏的实际表现,如果光看这些指标没有直观的感受,可以看下图:

如果说左边是玩家经常会遭遇到的表面现象,那右边则是基于手游性能深挖后的问题本质。

为了让游戏的优化能够更加系统,更加有的放矢,腾讯WeTest将监控手游性能相关的每个指标,并根据测试的结果进行优化。

那么,先来说说手游性能的重头,内存指标的检测。为什么是重头呢?内存的占用过高通常会带来“游戏闪退”、“卡顿”、“系统重启”等现象,其中每一个结果基本都对游戏的体验是致命的。我们从腾讯WeTest平台的Cube工具出发,通过简单的三步,介绍如何通过内存的检测,发现内存管理的问题,优化手游的性能。

第一步:测试游戏apk

首先要注意:手机必须root

1.安装WeTest助手

登录WeTest官网,在“产品“菜单下选择”性能测试“,点击”Unity客户端性能测试“

或者直接登录,点击“Android版 下载”,也在页面末尾扫描二维码直接下载。

2.登录

安装好客户端后点击WeTest助手启动,选择一种账号登录方式登录。

3.测试

测试类型选择“Cube”。

  • 首先确认“手机状态”为”手机已Root“;
  • 点击“应用选择”选择需要测试的应用(选择Unity游戏) ,非Unity游戏可以点击“通用性能检测”

  • 选择测试类型,测试类型分为四类:Unity性能测试(标准)、Unity性能测试(重度)、Unity资源测试、Mono内存检测。 那么这时候,问题就来了,一般应该先开始进行哪项测试呢? 选项一:Unity性能测试(标准) 首先我们看第一个,Unity性能测试(标准),该测试主要满足Unity引擎游戏日常性能审核的测试需求,覆盖FPS、CPU、PSS、Mono内存峰值四个维度;建议使用该测试获取准确性能数据,了解游戏的一个整体的性能表现,如果测试结果良好,说明游戏目前的性能表现已经非常好了,可以不需要进行很大程度的优化;如果测试结果不好,则可以考虑进行其他的测试模块。 选项二:Unity性能测试(重度) 该测试在性能测试(标准)的基础上,增加了函数耗时统计、单个FPS点中各帧的帧时间、Drawcall数量及每个函数具体出现的位置;建议使用该测试定位性能问题,为之后的性能优化做准备。 选项三:Unity资源测试 该测试可以获取游戏过程中多种资源数据,包括资源重复率、GameObject数量 、2D纹理大小 、网格大小 、动画剪辑大小 、音频大小 、关卡间保留资源 、Material对象拷贝数量等。建议在对内存优化进入到了资源阶段的时候,可以进行这个测试。 选项四:Mono内存检测 该测试提供了获取快照点的Mono内存对象情况(对象类型、对象大小、对象堆栈、对象引用关系 等);建议在定位存在问题的内存时,可以进行这个测试。
  • 确定测试类型之后,点击“开始测试”

a.Unity性能测试(标准)、Unity性能测试(重度)、Unity资源测试中都可以通过点击“开始记录”、“结束记录”来记录核心场景的性能数据、资源数据。

b.Mono内存检测中通过点击“mono内存快照”获取当前mono内存的详细情况,单次测试中可以任意在需要快照点的位置设置快照。

  • “上传”,退出游戏,选择测试游戏的游戏类型(最多选择两类),点击“确定”,在弹出的上传页,点击“上传”,完成数据的上传。
    4.日志日志主要是记录历史测试数据,显示历史测试中数据是否上传的状态,绿色为“已上传”,红色为“未上传”。通过点击“清空历史记录”可以清除客户端的日志中记录的历史数据。
    第二步:查看报告中的内存情况点击“我的主页”
    测试类型选择“Cube
    找到测试报告,点击“查看”
    第三步:分析报告如果要对手游内存管理进行优化,首先要明确一个分析的策略,Cube团队的建议是看四块内容:
  • 了解手游内存整体表现
  • 通过mono内存查看是否发生内存泄漏
  • 通过mono快照定位存在问题的内存
  • 通过内存分配总表定位存在问题的函数

了解手游内存整体表现

要观察手游内存的整体表现,首先观察游戏的堆内存峰值是否超过了建议值,如下图:

其中,建议值的来源是根据腾讯内部的性能标准,对手机的配置等级而形成的内存阈值,图中的高配机型,PSS内存峰值到达450MB或者mono内存到达50MB的时候就会开始预警。

如果需要更加详细的指标情况,可以选择“性能报告”部分中的“mono内存”:

如下图,我们可以看到内存峰值的超标线,如果超过,那么那一刻你的游戏极有可能出现上述“闪退”,“卡顿”和“系统重启”的现象了;如果没有超过,那么恭喜你,继续进入下一个关卡,检查你的游戏是否存在内存泄漏的现象。

通过mono内存查看是否发生内存泄漏

对于目前绝大多数基于Unity引擎开发的项目而言,其托管堆内存是由Mono分配和管理的。“托管” 的本意是Mono可以自动地改变堆的大小来适应你所需要的内存,并且适时地调用垃圾回收(Garbage Collection)操作来释放已经不需要的内存,从而降低开发人员在代码内存管理方面的门槛。

那么我们所说的内存泄漏情况,就是游戏在调用了一些资源结束之后(比如MOBA游戏中的5V5副本),没有及时的释放这些内存,从而导致堆内存的大小越来越多,从而超过了手机内存的阈值。

在比较合理的内存策略下,mono内存应该上升到一定阶段之后便不再变化,如下图:

如果内存产生了泄漏,便有可能出现下图的情况,堆内存的数值阶段性的不断提升。

如果你的游戏堆内存出现了不断上升的情况,需要排查一些内存泄漏的原因,可以进入下一个阶段,检查具体场景中内存的分配情况。

通过mono快照定位存在问题的内存

对于mono内存泄漏,一般只能通过猜测+不断修改代码测试的方法来修复问题,效率很低,腾讯WeTest平台的Cube工具提供了mono内存快照对比的功能,并包括对象分配堆栈,对象引用关系等详细信息,是定位mono内存泄漏问题的一大利器。在具体操作中,需要我们进行一次“mono内存检测“,具体操作可见上文”第一步“和”第二步“。

在“mono内存检测“的测试报告中,我们可以发现测试报告对每个场景都进行了标记,形成了一个”snapshot(快照)“,对比两次snapshot,查看两者之间的新增对象:

这些不同的snapshot内存使用情况的波动意味着游戏在进行游戏内存分配和释放,通过对这些snapshot进行对比,可以发现哪些内存新增了,哪些内存保留了,从而找到游戏在内存分配上产生的问题,那么如何进行操作呢?

如上图所示,在“mono内存检测“的测试报告中,每两个snapshot都可以进行对比,通过鼠标单击就可以选择,选中两个场景之后就可以点击”提交对比“:

点击之后会得到两个场景之间的内存分配比较,其中”对象堆栈“就代表游戏中实现的一个对象,以MOBA游戏为例,上图中的snapshot1和snapshot2所对应的两个场景可能就是“5V5战斗副本“和”游戏大厅“,通过右上角的”快照间新增top50“和”快照间保留top50“,我们可以了解到这两个不同的场景之间,哪些对象的资源被保留了,哪些对象的资源新增了(如果需要更多数据,可以点击右上角的”下载对比报表“),而这些行为是否是游戏程序所需要的。

可以看到,按钮按下前后新增的最大对象即为代码中生成的Byte对象,并且该对象被引用的次数为1。

那么,如何在游戏运行中看待这种快照之间新增或保留堆栈的现象?

比如说,王者荣耀这类MOBA游戏在副本和游戏大厅之间,会保留地图和NPC的对象资源,保证下次开始游戏时可以更快的读取和进入游戏;

而天天酷跑之类的跑酷游戏在在副本和游戏大厅之间,就不会保留地图和NPC的对象资源,原因就在于王者荣耀这类的MOBA游戏,地图和NPC的出现的情况是完全相同的,为了更好的游戏体验,保留对象资源是合适的;而天天酷跑之类的跑酷游戏,有不同的关卡副本,如果保留对象资源,会导致内存不断的被占用,因此选择不保留对象资源。

因此我们可以说,内存分配是否合理没有绝对意义上的标准,都要游戏开发者根据自己的开发策略,结合mono内存检测的报告,判定内存分配的情况是否在自己的计划之中。

通过内存分配总表定位存在问题的函数

重新刷新一下报告,我们最后来看一下游戏整体运行过程中具体功能的内存分配的情况:

图中的”分配堆栈“代表的就是游戏每次调用的一个函数,开发人员需要关注右上角”分配总次数“和”分配总大小“,关注是否有函数频繁分配内存,根据计划中的内存分配和实际的内存分配情况,开发人员应该进行针对性的优化。

测试报告分析到这里,基本可以发现内存管理方面存在的一些分配方面的问题了,但是内存优化的道路,到这里才完成了一半,Unity游戏在运行时的内存占用情况可以用下图表示:

Mono内存和native内存是PSS内存主要的组成部分,mono内存更多的起到内存调用的功能,因此常常成为了开发人员优化内存的起点;而native内存中包含了大量对象的资源,也是内存优化中的重要部分,这部分内容在测试报告中也有具体的细分,如下图:

这部分的内存检测,将在后面的干货中继续介绍。

针对手游的性能优化,腾讯WeTest平台的Cube工具提供了基本所有相关指标的检测,为手游进行最高效和准确的测试服务,不断改善玩家的体验。目前功能还在免费开放中。点击立即体验!

商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处。

原创声明,本文系作者授权云+社区-专栏发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

编辑于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Linyb极客之路

你的项目应该如何正确分层?

说起应用分层,大部分人都会认为这个不是很简单嘛 就controller,service, mapper三层。看起来简单,很多人其实并没有把他们职责划分开,在很多...

1143
来自专栏成长道路

org.apache.spark.sql.AnalysisException: Table or view not found: `traintext`.`train`; line 1 pos 14;

恭喜老铁,跟我遇到了一样的问题,接下来是解决方法: 遇到的问题: org.apache.spark.sql.AnalysisException: Table o...

7100
来自专栏CSDN技术头条

如何处理变慢的API?

在开始时表现良好的API会随着时间的推移而导致性能降低。学习如何管理和解决这些性能问题是开发者必须具备的技能之一。 作为一名工程师,你花了很多时间在API上——...

1917
来自专栏SAP最佳业务实践

SAP最佳业务实践:FI–应收帐款(157)-2客户主数据

4 流程步骤 4.1 创建客户主记录 在此活动中,可以创建客户主记录。 要执行该活动,使用此凭证中的主数据,运行创建客户主数据 (155.18)业务情景中的...

2583
来自专栏数说戏聊

Tableau构建销售监测体系(初级版)1.商业理解2.基本分析流程3.多数据源融合4.Top客户监测表制作

802
来自专栏美团技术团队

美团点评广告实时索引的设计与实现

2063
来自专栏Hadoop数据仓库

HAWQ取代传统数仓实践(十五)——事实表技术之无事实的事实表

一、无事实事实表简介         在多维数据仓库建模中,有一种事实表叫做“无事实的事实表”。普通事实表中,通常会保存若干维度外键和多个数字型度量,度量是事实...

1817
来自专栏JAVA高级架构

多研究些架构,少谈些框架(2)-- 微服务和充血模型

上篇我们聊了微服务的DDD之间的关系,很多人还是觉得很虚幻,DDD那么复杂的理论,聚合根、值对象、事件溯源,到底我们该怎么入手呢? 实际上DDD和面向对象设计、...

2805
来自专栏CSDN技术头条

微博广告推荐中有关Hadoop的那些事

一、背景 微博,一个DAU上亿、每日发博量几千万的社交性产品,拥有庞大的数据集。如何高效得从如此规模的数据集中挖掘出有价值的信息,以增强用户粘性,提高信息传播速...

1885
来自专栏腾讯大数据的专栏

Storm上的实时统计利器-easycount

背景 Storm是TRC(腾讯实时计算)平台的核心组件。与Hadoop不同,storm之上没有像hive,pig之类的解放应用开发人员效率的工具。开发原生的st...

2669

扫码关注云+社区