Unity编辑器edit mode进入play mode时间优化

发布时间 2023-09-01 14:45:17作者: dewxin

简介

最近需要利用他人打包好的资源,接近8G,不是很大,但解压完小文件特别多,到了unity里面会频繁显示repaint提示窗,降低了开发效率。
于是采用了进游戏即时解包的策略,虽然资源可以在需要时再加载,但资源的索引需要在进入游戏时就构建好。构建资源id到文件偏移位置的映射,单线程需要花费近30s。

作者首先通过了多线程处理多个资源包的方法,以及对IO进行了稍微优化,在打完包后能达到 平均时间8s 完成加载的效果。但不知道为什么,在编辑器中依然需要平均时间15s 左右的时间(不包含domain reload所需时间)。

接着又通过将计算结果以资产形式存储在场景中的方式,将进入play mode时间缩减到平均时间10s (包含domain reload所需时间)。

问题

从edit模式进入play模式后,需要解包索引部分的数据。构建资源id到文件偏移位置的映射,需要消耗大量的CPU资源。

解决方案

一开始想到的是利用多线程加速计算。但即使如此也无法达到预期的效果。

由于资源包不会发生变化,因此将计算好的数据保存起来,进入play mode的时候再【内存】读取也是一种可选方案。

比较直观的想法是将数据保存在编辑器环境,令其不受进入退出play mode的影响,以及修改代码导致的assembly reload的影响。

domain reloading

一开始查询到的资料和domain reloading相关。Domain reloading会重置你代码的状态,相当于你打包后第一次启动游戏。但Domain reloading会消耗时间,并且和代码文件的个数和复杂度成正比。

Domain reloading的细节可以看这篇文档,可以看到domain reloading会先执行从MonoBehaviours到AppDomain以及JITInfo的销毁操作,再执行从Assembly加载到Unity objects反序列化的初始化操作。

.
粗看的话,在编辑器中关闭domain reloading一方面可以保留我们的计算结果,另一方面可以省去domain reloading的开销,是一箭双雕之举。

但它无法避免修改代码带来的domain reloading,并且如果没有domain reloading提供的状态重置,那么我们需要手动重置游戏内状态,增加了额外的负担。

Unity native memory

根据Unity手册,场景和资产是存储在native memory的,我们可以将计算好的数据以资产或者场景的形式存储。这样当我们修改代码,或者进入游戏时,不会因为C#的domain reload而需要重新计算。

Unity stores the scenes in your project, assets, graphics APIs, graphics drivers, subsystem and plug-in buffers, and allocations inside native memory,

但此举似乎会增加 反序列化所需的时间,从而增加了domain reloading的开销。

另外场景中的脚本的字段如果太大也会导致编辑器卡顿,需要对其gameobject设置hideFlag,仅仅字段设置HideInInspector似乎不起效果。

总结

需要在游戏运营的前期就把控好资源的大小和个数。

参考

Unity 内存

Unity Domain Reload

Unity Domain Reload 细节