内存是Unity手游的硬伤,如果没有做好内存的相关管理和详细的测试,游戏极有可能出现卡顿、闪退等影响用户体验的现象。在此,笔者为我们介绍了一些Unity手游内存分析和测试过程中比较实用的测试场景案例、分析方法和解决方案等。由于Android和iOS分析思路比较类似,在这里我们仅拿iOS内存分析和测试为例,供大家参考。
测试目标
保证1G内存的iOS设备(iPhone 6、iPhone 6 Plus等)可在长时间持续游戏不闪退,同时优化已知的内存占用过高问题。
测试分析
由于已知游戏内存占用过高,针对这一问题,要搭建测试环境,模拟玩家的实际操作以及外网的实际情况,测试内存的使用情况。一般分为基础测试、压力测试和其他测试。
- 基础测试,即各种基本操作测试,比如场景切换操作、UI界面操作等;
- 压力测试,即多角色操作测试,比如角色的加载、角色的复杂程度、技能和动作的释放、上线下线操作等等,比如模拟多角色野外场景压力测试等;
- 其他测试,比如Xcode的相关工具使用分析等;
在测试中统计各操作对内存增长的贡献,分析可能的原因,并基于测试结果提出合理的优化方案。
测试思路
◆◆◆
基础测试
对于基础测试这一部分,可做的测试较多,我们仅拿UI界面操作测试和场景切换测试为例。
1. UI界面操作测试
主角进入指定场景的固定位置,尽量重复操作所有能操作的UI界面,采样对比前后的内存增长。
测试结果:
对比两次采样结果,单纯的界面操作行为,内存总共增长了140M,其中增长最多的是UITexture,剩余的主要是AnimationClip、AnimatorController和其他Texture等。
测试结果分析:
为何UITexture界面贴图会占用这么多的内存呢?
经分析,为了解决Android平台下打开界面响应过慢的问题,我们对UI界面采用了缓存机制。但是在iOS平台下,首先iPhone的反应速度要优于Android;其次iOS平台(如iPhone 6内存只有1G的设备)对应用程序的内存使用占比控制比Android平台更为严格,超过一定阀值系统会自动结束该进程。因此在iOS平台下,速度与内存要兼顾,尽可能节约对内存的使用。
针对这个问题可以修改界面缓存策略:
- 根据界面优先级、重要性进行划分,择优缓存;
- 部分大图集拆小、允许少量小贴图元素冗余;
在后续的优化中,程序修改了界面缓存策略,单纯UITexture方面就减少了约80M!如果你的项目也有这方面的需求,非常值得一试哦!
2. 场景切换测试
指定A场景的一个固定位置,主角从A场景切换到B场景,然后从B场景切换到A场景,重复切换多次后,最终回到A场景的固定位置,采样对比前后的内存增长。
测试结果:
对比场景切换前后的内存使用情况,发现无明显的变化。
测试结果分析:
场景切换前后内存无增长,基本保证了切换场景逻辑无内存泄露。反之,在测试中如果内存增加较多,则需要查看代码逻辑修复问题。
◆◆◆
压力测试
对于压力测试这一部分,由于情况比较多,操作比较复杂,所以要仔细测试。
为何要模拟外网真实环境进行测试呢?
首先就是可能无外网真实环境可用,这个没有办法,只能模拟;其次是外网真实环境过于复杂不利于有效的分析;再次就是外网真实环境不能随时重现利用,并长时间供测试人员分析,所以要尽量去模拟外网环境。
我们就以模拟多角色野外场景压力测试为例,进行迭代优化。由于需要模拟多人PK的情景,所以我们自己制作了机器人来方便定位并分析多人情况下的性能和内存问题。
1. 模拟多角色野外场景压力测试
模拟测试场景一:
选中一个野外场景A,主角和大量随机门派、随机外观的机器人进入场景,随机释放技能,然后机器人全部下线。分不同情况采集数据对比内存增长,在机器人全部下线后,主角切换到场景B,再切回测试场景A的原始位置,采集数据对比内存增长。
测试结果:
机器人上线后各种不同场景下的内容变化情况如下:
机器人静止时,内存对比空场景,增长97.5M;
机器人释放技能平稳后,内存对比空场景,增长119.4M;
机器人全部下线,内存对比空场景,依然增长98.3M;
机器人全部下线后,主角切换场景,再切回测试场景,内存对比空场景,基本无增长。
测试结果分析:
通过上述的测试及结果,结果分析及可获得的信息如下:
机器人全部下线后,由于大部分资源进入缓存池,故内存有增长是正常的;
机器人全部下线并切换场景后,对比空场景基本无增长,说明缓存池已全部卸载,故切换场景的缓存池释放逻辑正确、无泄漏;
角色相关的绝大部分资源保存至缓存池,切换场景后,所有进入缓存池的资源全部卸载,这一过程看似合理,但存在风险隐患:单场景内存峰值存在过高的风险。
单场景内存峰值存在过高的风险,究竟会有多高、缓存池到底有无泄露呢?
我们来进一步优化当前的测试环境:既然资源会进缓存池,那么我们放大它的影响,让资源不断进出缓存池。复杂化我们的测试场景,增加机器人不断上下线操作。
2. 模拟多角色野外场景压力测试 2.0
模拟测试场景二:
迭代优化“模拟测试场景一”,选中一个野外场景A,主角和大量随机门派、随机外观的机器人进入场景,在随机时间点,机器人不断的上下线,在线期间随机释放技能,每隔五分钟采样数据。
测试结果:
a. 采样数据:
13min 后游戏闪退。
b. 数据截图:
5:15:37数据截图
5:20:55数据截图
5:25:02数据截图
测试结果分析:
Material、AnimatorOverrideController、Mesh均在持续增长,我们的缓存池存在严重的资源泄露。剩下的问题就是解决泄露啦,相信我们程序GG,一定可以快速解决问题的!
在解决泄露问题后,我们的内存就真的没问题了吗?
我们需要进一步验证结果。在“多角色测试场景二”的基础上,我们还可以做些什么呢?和外网玩家实际情况相比,我们是不是还欠缺了一些东西呢?是的,比如频繁的聊天、UI界面操作、在地图内跑动等,再次复杂化测试场景。
3. 模拟多角色野外场景压力测试 3.0
模拟测试场景三:
迭代优化“模拟测试场景二”,选中一个野外场景A,主角和大量随机门派、随机外观的机器人进入场景,在随机时间点,机器人不断的上下线,在线期间随机释放技能、不停喊话,主角在野外场景中绕地图两圈后,选择固定点站立不动,用低配手机开到游戏内的最高配置,挂机半小时后,尽量重复操作可操作UI界面后,继续挂机半小时以上,间隔一定时间采集数据。
测试结果:
全程无闪退,内存峰值不超标。
测试结果分析:
为何要用低配手机开高配模式去测试呢?
因为外网玩家的环境总比我们内部模拟的环境要复杂的多,所以要尽可能以高标准要求整个游戏的质量。
为何要绕地图两周呢?
因为绕地图两周后,地图大部分资源就会进入缓存池中,内存会上升。
为何要挂机半小时后再去重复操作可操作的UI界面呢?
因为地图资源和角色资源该进缓存池的资源基本都进去了,再去操作UI界面,才是真正的内存压力瓶颈,可以撑过这个内存瓶颈,才能基本保证内存方面基本无重大问题。
这样复杂的测试环境下,低配手机若可以保证连续运行一个小时以上无闪退,内存峰值不超标,就基本保证了游戏内存方面无重大问题了。至此,该测试环境就可以作为发布版本前,必做的客户端内存压测案例之一了。
◆◆◆
其他测试
Unity手游需要做优化的东西非常非常多,而内存测试仅是其中的一个方向。本文所举案例中的大部分都可以用Unity自带的Profiler或插件进行测试,但这只能针对Unity自身可以抓取到的资源进行分析。若要分析整体内存的详细情况则需使用Xcode的相关工具。
- 通过Debug Navigator来观察App的Memory、CPU、FPS等整体情况;
- 通过Leaks分析内存泄漏;
- 通过AllocationsInstruments来收集所有的分配信息,比如:第三方库或服务的分配情况、苹果图形硬件驱动部分 (显存共享);Lua VM 分配和管理部分等。
Allocations Instruments收集所有的分配信息后,我们就可以针对分配次数多和分配尺寸大的模块进一步优化。同时,还需关注分配效率,因为分配得过于零碎,会导致利用率不高,往往还没有达到内存阀值就已经闪退了。
此外,还有一个便捷的途径,就是请UWA的专业团队来帮忙给项目做全方位的优化,包括性能诊断与优化、资源检测与分析等。该团队为我们项目做过优化,专业、细致、深入,整个过程收益颇多,有需求的团队不妨一试!(小编语:谢谢作者对UWA的支持和厚爱!)
鉴于此次的优化内存使用的经验与教训,作为测试人员,一定要认真细致地制定测试步骤并严格执行,善于从各种数据中理清头绪并定位出问题根本原因,以优化目标为导向,以当前的测试结果为修正值,不断地迭代优化测试环境,这样才能保证性能测试结果的正确性、发现项目中存在的严重问题、给出合理的优化方案及建议并最终保证游戏的质量。
以上的测试及观点,不免有遗漏或者不周、不妥的地方,欢迎拍砖、批评指正!