Unity3D实例:内存使用的分析实践
这是一次内存使用的分析实践,开发环境是 Unity 5.3.4p5 + uGUI
======
经过真机WeTest、adb shell、Unity MemoryProfiler、代码走读这几种手段观察,理解客户端的内存使用情况。
一、真机WeTest测试,并上传测试数据。
WeTest是一个测试插件,独立于游戏客户端本身。
操作①:启动游戏,打开根性忍传系统,打一局,胜利后回到主界面。
登录前后200M上下,战斗后超过360M,回到主界面也一直保持在360M。
操作②:退出重新进入游戏,并打开全部系统UI界面(不打开副本地图,也不进入战斗)。
登录前后200M上下,逐个系统UI界面打开,内存从220M缓慢增加,并最后基本保持在270M上下。
操作③:进入副本地图,并打第四章最后一关。
战斗开始后内存增长到了420M,回到主界面也一直保持在420M。
操作④:继续玩一局精英副本、一局普通副本、一次排位赛、一次根性忍传、跑一次组织护送,再次逐个系统界面点开一次(除了副本地图)。
内存增长到430M、440M。
从一次简单操作(操作①),以及一次完整操作(操作②③④),大致可看到:
除副本和战斗以外全部系统大概需要270M内存,而副本和战斗大概需要额外160M内存。
二、通过adbshell命令查看内存情况。
adb shell dumpsys meminfocom.tencent.narutotbs
游戏登录后:
一轮完整操作(上述操作②③④)后:
看到的Pss数据基本跟WeTest一致(WeTest内存值应是通过Linux命令获得的Pss数据)。
注意其中EGLmtrack和GL mtrack,以及诡异的Unknown部分的大小,它们之和基本上就是Pss的大小。
三、UnityMemoryProfiler观察
Unity5.3之后提供了一个更直观的内存工具:MemoryProfiler
游戏登录前的内存各资源类型分布:
其中Texture2D还不是大头,大约占1/5。
一轮完整操作(上述操作②③④)后的内存各资源类型分布:
其中Texture2D已然是大头。
两者对比看,登录前Texture2D只有13.3MB,而之后增加到了1.5GB。
由于编辑器的资源格式是ARGB 32bit,而打包成APK/IPA则采用压缩ETC/PVRTC 4bit,而且Unity MemoryProfiler会算双份(比如1024*1024*32bit显示8MB,实际应是4MB),
所以这里Texture2D实际占用大约是1.5GB/8/2=100MB。
Unity MemoryProfiler显示了每个图片资源被引用的Root节点,整理发现大头是以下这四个:
CommonResCache | 缓存VIew界面等Asset资源 |
BattleResCache | 缓存战斗内的忍者帧动画等资源 |
DungeonResCache | 缓存副本地图的背景图片等资源 |
IconResCache | 缓存忍者半身像、忍者头像Icon、技能Icon、道具Icon等资源 |
四、代码走查Cache使用
经过一轮完整操作(上述操作②③④)后,断点发现:
其中IconResCache缓存的资源key数量相对较多,这是因为它是按文件名+Sprite名综合索引。
这几个XxxResCache管理各自分类的资源Cache的加载与更新、淘汰与卸载。
而资源淘汰则根据不同机型有不同阈值与淘汰策略。
比如对于低端机,XxxResCache缓存数量更少,且退出战斗时清空BattleResCache。
IconResCache的淘汰策略相对特殊,仅对忍者半身像作淘汰,不对忍者头像Icon、技能Icon和道具Icon等资源作淘汰。这是因为忍者半身像是独立的图片资源,可以卸载任意一个或几个。
而其他Icon是整合在一张图片的,不能仅卸载其中某几个Icon,要想卸载就得卸载整张图片,但是下次使用又得重新加载整张图片,会引起额外的卡顿。此处考虑内存与CPU的平衡点。
不过,对于其中内容较“空”的资源,可考虑裁剪成多张尺寸小一号的资源,比如下面的道具Icon、忍者Icon、技能Icon。
但是资源裁切又会引入额外Drawcall,以及增加资源维护成本(增加字段、额外配表)。此处考虑内存与GPU、资源维护的平衡点。
为了实现重力感应的效果,主界面把背景图片裁成远近不同的几个子图片。从策划角度可以考虑下如何优化内存。普通副本大章选择界面也是类似。此处考虑内存与游戏体验的平衡点。