找回密码
 立即注册
查看: 543|回复: 3

Unity游戏引擎游戏开发时遇到内存泄漏问题怎么办?

[复制链接]
发表于 2021-1-7 09:25 | 显示全部楼层 |阅读模式
自研发的Unity游戏老是卡顿、闪退,有什么办法解决吗?
发表于 2021-1-7 09:27 | 显示全部楼层
内存泄露是开发人员在项目研发过程中最常见也最不愿遇到的问题。就目前来看,大家对于判断项目是否存在内存泄露仍然存在一些误区:
    误区一
    我的项目进出场景前后内存回落不一致,比如进入场景后,内存增加40MB,出来后下降30MB,仍有10MB内存没有返回给系统,即说明内存存在泄露情况。误区二
    我的项目在进出场景前后,Unity Profiler中内存回落正常,但Android的PSS数值并没有完全回落(出场景后的PSS值高于进场景前的PSS值),即说明内存存在泄露情况。
以上是我们遇到的开发团队反馈给我们的典型问题。相信大多数开发团队都会遇到类似的情况。在此有必要说明一下,以上两种情况均不能表明内存存在泄漏问题。即便内存在一段时间始终保持增长的趋势,也不能简单地判定其存在内存泄露。因为造成内存不能完全回落的情况有很多,比如资源加载后常驻内存以备后续使用、Mono堆内存的只升不降等等,这些均可造成内存无法完全回落。一般来说,我们推荐的判断内存是否泄漏的方法如下:

一、检查资源的使用情况,特别是纹理、网格等资源的使用
在我们进行过的项目深度优化过程中,资源泄漏是内存泄露的主要表现形式,其具体原因是用户对加载后的资源进行了储存(比如放到Container中),但在场景切换时并没有将其Remove或Clear,从而无论是引擎本身还是手动调用Resources.UnloadUnusedAssets等相关API均无法对其进行卸载,进而造成了资源泄露。对于这种情况的排查相当困难,这是因为项目中的资源量过于巨大,泄露资源往往很难定位。因此,我们在UWA测评报告中对项目中的每个资源都进行了详细的监控,并通过“生命周期”这一衡量指标让大家可以清楚地了解到每个资源在项目运行过程中的使用范围。


这样,大家可以通过资源的“生命周期”属性来快速查看有哪些资源是“常驻”内存的,并且判断该资源是“预加载”资源还是“泄露”资源。
同时,项目中所使用的总资源数量往往是成百上千的,让大家逐个资源检查过来是一件很费力的事情。所以,我们推出了资源的“场景比较”功能。建议大家通过以下两种方式进行资源比较,以便更快地找到存在“泄露”问题的资源
    同种类型场景或同一场景进行比较
一般来说,同种场景或同一场景的资源使用应该是较为固定的,比如游戏项目中的主城场景或主界面场景。通过比较不同时刻同一场景的资源信息,可以快速帮你找到其资源使用的差异情况。这样,你只需判断这些“差异”资源的存在是否合理,即可快速判定是否存在资源泄露,已经具体的泄露资源。
    不同类型场景进行比较
除一些常驻资源外,不同类型的场景,其资源使用是完全不同的。比如,游戏中主城和战斗副本的资源,除少部分常驻内存的资源外,二者使用的绝大部分资源应该是不一致的。所以,通过比较两种不同类型的场景,你可以直接查看比较结果中的“共同资源”,并判断其是否确实为预先设定好的常驻资源。如果不是,则它很可能是“泄露”资源,需要你进一步查看项目的资源管理是否存在漏洞。
二、通过Profiler来检测WebStream或SerializedFile的使用情况AssetBundle的管理不当也会造成一定的内存泄露,即上一场景中使用的AssetBundle在场景切换时没有被卸载掉,而被带入到了下一场场景中。对于这种情况,建议直接通过Profiler Memory中的Take Sample来对其进行检测,通过直接查看WebStream或SerializedFile中的AssetBundle名称,即可判断是否存在“泄露”情况。

三、通过Android PSS/iOS Instrument反馈的App线程内存来查看承接上述“误区二”中的说法,“Unity Profiler中内存回落正常,但Android的PSS数值并没有完全回落”是有可能的,这是因为Unity Profiler反馈的是引擎的真实分配的物理内存,而PSS中记录的则包括系统的部分缓存。一般情况下,Android或iOS并不会及时将所有App卸载数据进行清理,为了保证下次使用时的流畅性,OS会将部分数据放入到缓存,待自身内存不足时,OS Kernel会启动类似LowMemoryKiller的机制来查询缓存甚至杀死一些进程来释放内存。因此,并不能通过一两次的PSS内存没有完全回落来说明内存泄露问题。
我们推荐的测试方式是在两个场景之间来回不停切换,比如主城和战斗副本间。理论上来说,多次切换同样的场景,如果Profiler中显示的Unity内存回落正常,那么其PSS/Instrument的内存数值波动范围也是趋于稳定的,但如果出现了PSS/Instrument内存持续增长的情况,则需要大家注意了。这可能有两种可能:
    Unity引擎自身的内存泄露问题。这种概率很小,之前仅在少数版本中出现过。
    第三方插件在使用时出现了内存泄露。这种概率较大,因为Profiler仅能对Unity自身的内存进行监控,而无法检测到第三方库的内存分配情况。因此,在出现上述内存问题时,建议大家先对自身使用的第三方库进行排查。
关于Unity内存方面的问题,建议通过查看UWA Blog的两篇内存优化文章,基本上目前研发团队遇到的95%的内存问题,通过这两篇文章都可以找到相应的办法来进行解答。
性能优化,进无止境
性能优化,进无止境---内存篇(下)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
发表于 2021-1-7 09:28 | 显示全部楼层
游戏中大部分mono内存泄漏的情况都是由于静态对象的引用引起的,因此对于静态对象的使用需要特别注意。
内存是手游的硬伤——Unity游戏Mono内存管理与泄漏- 知乎专栏介绍了在腾讯游戏在Unity游戏开发过程中常见的Mono内存管理问题,并介绍了一系列解决的策略和方法。
发表于 2021-1-7 09:35 | 显示全部楼层
在编辑状态先测试运行,查看占用的内存。再根据实际硬件情况对游戏中的资源进行修改,避免运行时的内存泄漏导致闪退。
卡顿的话就用profiler查看,把函数中耗时的部分拆帧。
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-9-20 10:55 , Processed in 0.093218 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表