明绍宗朱聿键鼻 发表于 2020-12-21 11:00

Unity 断言 'meshVD.GetDataPtr() == NULL' 问题分析

最近写的几篇文章都记录一些诡异问题的分析过程,之所以记录这些,我想解决问题过程当中的思考过程远比结论更有意义。

再吐槽下吧,某乎把我之前写的Switch漏洞分析的文章删除了,删除理由违法违规,反正理都在你那,人为刀俎我为鱼肉,所以挪步到Github了。被删的文章名为:Nintendo Switch 破解原理:详解 Fusée Gelée 漏洞。
公开领域的漏洞报告,并且厂商已经修复的漏洞都不能讨论,这的确是片没有知识的荒原。Unity 2018.3更新后引入了一个很严重的内存泄露问题,每次切换场景内存都会不断增长。
如果不关心分析过程请直接看结论:如果是2018.3.4之前的版本,请升级引擎
通过Profiler分析,内存增长在 Objects 上,而这个分类正常情况下应该处在一个很低水平。
于是顺着这个线索展开问题分析。
由于没有引擎源码,只能通过在内存分配器上挂钩子打日志排查,钩子挂在
MemoryManager::AllocateMemoryManager::Deallocate
此外,有一个函数 MemoryManager::Reallocate用于Resize内存,不过内部也会调用Allocate和Deallocate所以只钩前两个就可以了。
日志中记录了是分配还释放,对应的内存地址,内存大小,分配的文件和行号(调试信息)
通过反复切换场景,统计分析后确认有很大一部分内存Allocate后没有Deallocate。
于是需要进一步分析,到底是是什么数据发生内存泄露。
根据文件名归类后,发现内存增长主要来自 Mesh.cpp。
于是就需要分析Mesh是如何发生内存泄露的,在构造和析构上打印日志分析后发现Mesh本身都是正常分配和释放的,同时Profiler里也没有发现有Mesh泄露,这样的话,最可疑的就是Mesh在堆上分配的内存发生泄露。
Mesh分配堆内存的地方有点多,正在一筹莫展的时候,在编辑器下加载AssetBundle跑游戏注意到了一个断言:
Assertion failed on expression: 'meshVD.GetDataPtr() == NULL'
把这句放到粘贴到搜索引擎里一搜,发现了这个issue
EDITOR CRASHES WHEN LOADING A MESH ASSET WITH 'MESH COMPRESSION' FROM AN ASSETBUNDLE
这个issue case的讨论中,提到了 Assetbundle 和 Mesh Compression。虽然页面中显示Verified FIXED 2018.1.0b5, 2018.2.0a3,但还是决定顺着这个思路做下尝试,谁说修好的Bug就真的修好了呢?
经过一番努力,我们测试出来,只要从AB包中加载开启压缩的网格就会报这个断言。关闭网格压缩后,断言消失。断言出现时,Objects内存增长。
到了这一步,我们用更新的版本2018.3.6做了测试,发现还是存在内存泄露,实在让人丧气。但这一点后来证明在于我们的打包文件中存在一些老版本的AB包,导致了这个误判,事实上这个问题在2018.3.4已经修复。
正因为误判,产生了做hackfix的想法,要做hackfix势必要更加了解这个bug产生的原因。针对断言的上下文做了一些分析。
这是Mesh的AwakeFromLoadThreaded函数中部分逻辑,如果mesh->collisionMeshData不为空就调用 CollsionMeshData::AwakeFromLoadThreaded,其中要求meshVD(Mesh Vertex Data)此时为 NULL,然后把某份数据给到它后,AwakeFromLoadThreaded重新置为NULL,根据上下文猜测,这个临时设置的数据,是适用于CollsionMeshData的,解压后的数据。由于Unity的bug,这个meshVD的指针此时已经有值了,被覆盖后,这份meshVD就泄露了,Mesh析构的时候已经找不到这份meshVD了。
此时Hackfix的思路是给这个存在问题的函数打上二进制补丁,meshVD不为空时,保存指针,CollsionMeshData::AwakeFromLoadThreaded后还原meshVD。
不过这个Hackfix并没有付诸实施,因为此时又确认了一遍bug在新版本是否存在,清空了目录走了打完整Assetbundle的流程。后发现这个问题已在新版本修复。
经过测试之后,发现问题是在 2018.3.4 中修复的,翻阅了Release Note注意到这么一句:
Build Pipeline: Fixed crash when loading compressed meshes out of asset bundles. (1115334)
虽然我没遇到crash,但是如果Mesh够多的话,在低内存的设备上也是会crash的(我只能这么安慰自己了,哈哈)
页: [1]
查看完整版本: Unity 断言 'meshVD.GetDataPtr() == NULL' 问题分析