2025年度大赏 | UWA问答精选

2025年度大赏 | UWA问答精选

时光流转,深耕不辍。UWA知识型栏目《厚积薄发 | 技术分享》已悄然陪伴大家走过459个工作周。在这一年的技术征途里,我们依旧扎根真实的游戏开发场景,以问答社区的经验沉淀为基石,又迎来了UWA AI技术的全新助力。

2025年的十大精选内容,既收录了社区开发者们互助探讨的智慧结晶,也融入了UWA AI基于海量知识沉淀的精准解答,每一篇分享都瞄准开发中的痛点卡点,为大家提供切实可行的破局思路。

回望这一年,是无数开发者的踊跃分享与积极互动,让技术的价值持续传递;展望2026年,UWA问答社区与UWA AI问答将继续并肩前行,以更专业的内容、更高效的解决方案,陪伴每一位开发者在技术深耕之路上稳步迈进!

UWA 社区主页:community.uwa4d.com
UWA QQ群:793972859

From 问答社区

TOP1:如何让GameObject销毁时无论是否Active过,都调用OnDestroy?

请教一个问题,MonoBehaviour的OnDestroy方法,如果这个GameObject的实例化时就是隐藏的,销毁时不会调用OnDestroy方法。我们项目有些核心逻辑是基于这个OnDestroy做的(时间太久远,耦合太多逻辑不好改出去了)。有没有什么办法,可以让这个GameObject销毁时无论是否Active过,都调用OnDestroy。

A1:要触发OnDestroy,必须要触发过Awake(Awake可以不明着写出来),通常是被实例化或者第一次激活的时候触发Awake,如果一直处于不激活的状态,那么销毁的时候不会自动触发OnDestroy。所以可以在激活的父节点上主动SetActive一下:

A2:1. 一般一个Prefab本身是点亮的,大部分是里面的某些节点才会隐藏。如果是我说的这种情况,应该是在根Prefab摧毁的时候主动调用一次需要控制调用的子组件。

  1. 如果你真的是根Prefab就隐藏的那更简单了:
    (1)做一个工具扫描所有Prefab检查并且修改点亮情况;
    (2)编辑器模式下加载完一个Prefab之后检查是否点亮,如果没有则打印Error。

A3:我们也遇到了这个,主要导致的问题自定义组件清理不掉Lua注册过来的回调,导致返回登录报错。

我这边解决思路是,在脚本反序列化之后,将自己注册到UI根节点的管理脚本上,由这个管理脚本在Destroy时清理下面的子节点。Base脚本如下图:

有几个要点说明下:

  1. 我们只处理了UI(其他地方基本不会出这问题),项目的用法上每个UI根节点有必挂的组件,这个组件一定会执行Awake;
  2. 如果组件自身Awake走到了,就不需要额外的销毁管理,需要从管理器中将自己移除;
  3. 反序列化接口中有一堆限制,要小心处理,比如常用的接口只能在主线程执行,如果在子线程要跳过。还有Prefab打开的编辑状态也有一些状态取不到,我这边直接忽略了(因为不常用)。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/67d390183d306f3e9d594e7a


From UWA AI 问答

TOP2:Unity中可以禁用GC吗?

Unity中可以禁用GC吗?

A:在Unity中,可以禁用垃圾回收(GC),但需谨慎使用,并结合具体场景进行管理。

禁用GC的方法
Unity提供了通过脚本控制垃圾回收器行为的API:GarbageCollector.GCMode。

该API支持以下三种模式:

  • GarbageCollector.Mode.Enabled:默认模式,自动触发GC。
  • GarbageCollector.Mode.Manual:禁用自动GC,但可手动调用System.GC.Collect()或GarbageCollector.CollectIncremental()。
  • GarbageCollector.Mode.Disabled:完全禁用GC,包括手动调用也无效。

将GarbageCollector.GCMode设置为Disabled即可彻底关闭垃圾回收机制。

使用场景与最佳实践
禁用GC主要用于性能敏感的关键阶段,如战斗、加载、过场动画等,以避免GC导致的CPU卡顿(GC Spike)。

推荐做法:

  1. 预分配内存:在进入关键阶段前,预先分配所需的所有对象(如对象池、缓存等),确保运行时无新内存分配。
  2. 临时禁用GC:进入关键阶段时设置GCMode = Disabled,结束后立即恢复为Enabled或Manual。
  3. 手动清理:恢复GC后,调用System.GC.Collect()回收阶段性内存,防止堆持续增长。

    示例流程:
// 进入关卡前
AllocateLevelResources(); // 预分配资源
GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;

// 关卡运行中(避免任何new操作)

// 关卡结束
GarbageCollector.GCMode = GarbageCollector.Mode.Enabled;
System.GC.Collect(); // 回收内存

风险与注意事项

  • 内存持续增长:禁用GC后,未引用的对象不会被释放,若持续分配将导致内存溢出。
  • 必须严格控制内存分配:禁止使用字符串拼接、装箱、Linq、匿名函数等易产生GC的操作。
  • 推荐结合0GC编程:使用StringBuilder、对象池、结构体等技术实现运行时零托管内存分配。

辅助优化手段

  • 启用增量GC(Incremental GC):在Player Settings中开启Use Incremental GC,将GC工作分摊到多帧,减少单次停顿时间。
  • 性能监控:使用Profiler或UWA GOT工具监控GC Alloc值,定位内存分配热点。

综上,Unity支持运行时禁用GC,但应作为高阶优化手段,在可控内存分配的前提下短期使用,以换取更稳定的帧率表现。


From 问答社区

TOP3:为什么不应将游戏逻辑写在FixedUpdate中?

请问在向别人解释不要把游戏逻辑放在FixedUpdate,而应正常地放在Update里,除了Input事件外,我还能使用哪些理由呢?

A1:FixedUpdate只处理物理相关的逻辑,Input事件应该放Update。

A2:如果卡,FixedUpdate会在一帧里执行多次来追上更新次数,可能导致严重的掉帧和发热。若想慢点更新,建议用携程或者用UniTask。

我需要一些硬性的不能做的理由,目前想到的就只有Input事件会重复或被跳过。

A3:那Update里面干什么?而且位置更新不放到Update和渲染匹配不上,看着应该会有顿的感觉。

A4:FixedUpdate不能动态锁帧,全放里面手机发热发烫耗电也快。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/677b429f682c7e5cd61bf9e4


From 问答社区

TOP4:InstantiateAsync有什么需要特殊处理的吗?

请教个问题,InstantiateAsync有什么需要特殊处理的吗?我发现异步实例化出来的角色,好像丢了蒙皮一样,Mesh完全不跟着动画、还有根节点动,始终以T-pose的形态呆在固定位置,而且同一个角色,同步加载是正常的。

这是我这边的环境:

A1:我们在接近你的版本和更高版本试了下,分别复现了问题和正常加载。查了下可能是类似下面的Unity Bug(异步实例化相关的bug有很多),应该要升一下版本。

A2:的确升级Unity版本后ok了。

A3:没啥问题,效果也比较好、明显,总得来说异步实例化好处多余坏处,我是调研过了并且项目在使用的。

AsyncInstantiateOperation.GetIntegrationTimeMS() AsyncInstantiateOperation.SetIntegrationTimeMS()可以设置异步实例化的间隔时间,默认是2ms,是Unity 2022.3.20新增加的功能。

写代码的时候可以考虑Async/Await,当然国际版Unity最新.3.60,国内版.3.54。

如果你项目没啥特殊可以考虑升级到最新,正常来说如果你没有上线最好到最新或者你得平时关注Unity版本发布日志。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/67ce97913d306f3e9d594e6c


From 问答社区

TOP5:在Unity转微信小游戏下,如何用Worker实现多线程?

想用WebWorker计算Unity里的小球的运动轨迹,请问Unity转微信小游戏的情况下,可以用Worker实现多线程吗?

A:可以参考官方文档:https://developers.weixin.qq.com/minigame/dev/api/worker/wx.createWorker.html

功能描述:
创建一个Worker线程。

参数:
string scriptPath
Worker入口文件的绝对路径

object options:
可选参数:
属性:useExperimentalWorker
类型:boolean
默认值:false
必填:否
说明:是否使用实验worker。在iOS下,实验worker的JS运行效率比非实验Worker提升数倍,如需在Worker内进行重度计算的建议开启此选项。同时,实验Worker存在极小概率会在系统资源紧张时被系统回收,因此建议配合worker.onProcessKilled事件使用,在Worker被回收后可重新创建一个。
最低版本:2.13.0

返回值
Worker
Worker对象

注意事项

  • 接口使用前需要在game.json(插件为plugin.json)中配置workers字段,表示Worker代码根目录。
  • scriptPath为入口文件的绝对路径,且不以/开头。
  • 目前限制最多只能创建一个Worker,创建下一个Worker前请先调用Worker.terminate。
  • 多线程Worker指南(小游戏)。

示例代码

// 创建普通worker
wx.createWorker('workers/index.js')
function createNewWorker() {
  const worker = wx.createWorker('workers/index.js', {
    useExperimentalWorker: true
  })
  // 监听worker被系统回收事件
  worker.onProcessKilled(() => {
    // 重新创建一个worker
    createNewWorker()
  })
}
// 创建实验worker
createNewWorker()

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/67c559603d306f3e9d594e69


From 问答社区

TOP6:增量GC机制,会导致碎片化更严重吗?

请问增量GC这种频繁分配与释放的GC机制,会导致碎片化更严重吗?好像介绍增量GC的资料很少,所以有这种疑问。

A:对于碎片的产生,理论上增量GC和普通GC应该是没有什么区别的,都是标记-清除。增量GC只是把GC的工作分帧处理了,控制碎片的占用比例更关键的是要减少大块临时分配。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/684fe482682c7e5cd61bfaae


From 问答社区

TOP7:为什么场景中没有刚体更无碰撞事件,但仍有较高物理耗时?

我有个疑问:为什么GOT性能报告和Profiler里看物理模块耗时都很高?但其实这时候场景里已经没有刚体了,按理说不会发生碰撞,只有在代码里用了Raycast判断子弹命中,后来我把设置里的物理模拟关掉,又打了包,物理耗时确实降了下来,看子弹还是能正常命中(因为是代码调的),看粒子里的碰撞也还是能生效。

我不明白的是:之前那么高的物理耗时是在做什么?可能是什么导致的?是有一些我没留意到的地方用了物理导致的,还是说Unity机制如此?(Unity版本2022.3.59)

A:的确,当前Unity版本的机制就是这样,很多时候必须要关闭掉物理模拟(指把Simulation Mode改成Script)才可以节省耗时。具体机制是场景中只要Static Collider数量大于0且没有关闭物理模拟就会有耗时,和场景中有没有刚体、有没有发生碰撞事件无直接关联。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/684688ea682c7e5cd61bfaa0


From 问答社区

TOP8:如何用GPU Instancing来优化树木草石重复模型?

项目场景里的树木草石重复模型非常多,在尝试用GPU Instancing来优化。使用的Shader应该是SRP Batcher和GPU Instancing都支持的,但是材质勾上GPU Instancing后看FrameDebugger里还是走的SRP Batcher,要怎么修改比较好呢?

A:如果Shader两个都兼容,就会优先走SRP Batcher的。常规做法就是把规划要用GPU Instancing的物体用别的不走SRP Batcher的Shader;也可以考虑仍然用两个都兼容的Shader,但是用MaterialPropertyBlock打断SRP Batcher,这样就会顺延走GPU Instancing了。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/680dd4d53d306f3e9d594ecc


From 问答社区

TOP9:如何在运行时获取硬件信息?

请问怎样在运行时获取硬件信息?一般参考其中哪些信息进行分级比较合理?

A:一般是用SystemInfo里的一些接口,如图:

真机上输出效果如图:

一般用其中deviceType、deviceName去找对应的硬件档次划分;或者直接graphicsDeviceName给到的GPU型号进行画质分级。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/67f374e1682c7e5cd61bfa35


From 问答社区

TOP10:如何排查优化URP内置Shader冗余?

请教一下Shader冗余应该怎么查,似乎好几个Shader运行时都有两份?

A:资源冗余最常见的原因是AssetBundle没有依赖打包导致的,可以使用UWA的在线AssetBundle检测进行冗余检测先试试。

测了AssetBundle,确实有冗余,但AssetBundle冗余的Shader和运行时冗余的Shader好像又不一致。实际运行时的冗余都是Hidden/Universal Render Pipeline/xxx。这又是为什么呢?

A:这些是URP的Shader,通常是URP Asset的引用导致的,因为URP Asset会引用这些Shader。而内存中出现两份Shader,说明内存中出现了两个来源路径不一样的URP Asset,通常一份是在PlayerSetting中引用的URP Asset,另外一份可能来自AssetBundle中动态加载的URP Asset。RendererData里面会引用到PostProcessData,PostProcessData就会引用这些Shader,如果代码里面动态加载的AssetBundle里面也有这种资源,也会引用一份Shader进内存,就会造成冗余。

请问这个怎么处理,直接删去吗?

A:一般只处理内存占用比较大的即可,其他的内存占用比较小,冗余开销也不大。比如Hidden/Universal Render Pipeline/Uberpost,需要删除其中用不到的Keyword来降低占用;又比如Hidden/Universal Render Pipeline/HBAO,看是否确实要用到,用不到就解除引用。

欢迎大家转至社区交流:
https://answer.uwa4d.com/question/69245652244ce21ce9ec095c

无论是社区里开发者们的互助讨论,还是AI基于知识沉淀的快速反馈,核心都是为了让每一个技术难题都有解、每一次踩坑都有回响。本期分享分别来自UWA AI问答和UWA问答社区,希望这些从真实开发场景中提炼的经验,能直接帮你解决当下的技术卡点,也让你在遇到同类问题时,能更高效地找到破局方向。

封面图来源于网络


今天的分享就到这里。生有涯而知无涯,在漫漫的开发周期中,我们遇到的问题只是冰山一角,UWA社区愿伴你同行,一起探索分享。欢迎更多的开发者加入UWA社区。

UWA官网:www.uwa4d.com
UWA社区:community.uwa4d.com
UWA学堂:edu.uwa4d.com
官方技术QQ群:793972859