![]()
時(shí)光流轉(zhuǎn),深耕不輟。UWA知識型欄目《厚積薄發(fā) | 技術(shù)分享》已悄然陪伴大家走過459個(gè)工作周。在這一年的技術(shù)征途里,我們依舊扎根真實(shí)的游戲開發(fā)場景,以問答社區(qū)的經(jīng)驗(yàn)沉淀為基石,又迎來了UWA AI技術(shù)的全新助力。
2025年的十大精選內(nèi)容,既收錄了社區(qū)開發(fā)者們互助探討的智慧結(jié)晶,也融入了UWA AI基于海量知識沉淀的精準(zhǔn)解答,每一篇分享都瞄準(zhǔn)開發(fā)中的痛點(diǎn)卡點(diǎn),為大家提供切實(shí)可行的破局思路。
回望這一年,是無數(shù)開發(fā)者的踴躍分享與積極互動,讓技術(shù)的價(jià)值持續(xù)傳遞;展望2026年,UWA問答社區(qū)與UWA AI問答將繼續(xù)并肩前行,以更專業(yè)的內(nèi)容、更高效的解決方案,陪伴每一位開發(fā)者在技術(shù)深耕之路上穩(wěn)步邁進(jìn)!
UWA 社區(qū)主頁:community.uwa4d.com
From
問答社區(qū)
TOP1:如何讓GameObject銷毀時(shí)無論是否Active過,都調(diào)用OnDestroy?
請教一個(gè)問題,MonoBehaviour的OnDestroy方法,如果這個(gè)GameObject的實(shí)例化時(shí)就是隱藏的,銷毀時(shí)不會調(diào)用OnDestroy方法。我們項(xiàng)目有些核心邏輯是基于這個(gè)OnDestroy做的(時(shí)間太久遠(yuǎn),耦合太多邏輯不好改出去了)。有沒有什么辦法,可以讓這個(gè)GameObject銷毀時(shí)無論是否Active過,都調(diào)用OnDestroy。
A:要觸發(fā)OnDestroy,必須要觸發(fā)過Awake(Awake可以不明著寫出來),通常是被實(shí)例化或者第一次激活的時(shí)候觸發(fā)Awake,如果一直處于不激活的狀態(tài),那么銷毀的時(shí)候不會自動觸發(fā)OnDestroy。所以可以在激活的父節(jié)點(diǎn)上主動SetActive一下:
![]()
A2:1. 一般一個(gè)Prefab本身是點(diǎn)亮的,大部分是里面的某些節(jié)點(diǎn)才會隱藏。如果是我說的這種情況,應(yīng)該是在根Prefab摧毀的時(shí)候主動調(diào)用一次需要控制調(diào)用的子組件。
![]()
2. 如果你真的是根Prefab就隱藏的那更簡單了:
(1)做一個(gè)工具掃描所有Prefab檢查并且修改點(diǎn)亮情況;
(2)編輯器模式下加載完一個(gè)Prefab之后檢查是否點(diǎn)亮,如果沒有則打印Error。
A3:我們也遇到了這個(gè),主要導(dǎo)致的問題自定義組件清理不掉Lua注冊過來的回調(diào),導(dǎo)致返回登錄報(bào)錯(cuò)。
我這邊解決思路是,在腳本反序列化之后,將自己注冊到UI根節(jié)點(diǎn)的管理腳本上,由這個(gè)管理腳本在Destroy時(shí)清理下面的子節(jié)點(diǎn)。Base腳本如下圖:
![]()
有幾個(gè)要點(diǎn)說明下:
1. 我們只處理了UI(其他地方基本不會出這問題),項(xiàng)目的用法上每個(gè)UI根節(jié)點(diǎn)有必掛的組件,這個(gè)組件一定會執(zhí)行Awake;
2. 如果組件自身Awake走到了,就不需要額外的銷毀管理,需要從管理器中將自己移除;
3. 反序列化接口中有一堆限制,要小心處理,比如常用的接口只能在主線程執(zhí)行,如果在子線程要跳過。還有Prefab打開的編輯狀態(tài)也有一些狀態(tài)取不到,我這邊直接忽略了(因?yàn)椴怀S茫?/p>
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/67d390183d306f3e9d594e7a
From
UWA AI 問答
TOP2:Unity中可以禁用GC嗎?
Unity中可以禁用GC嗎?
A:在Unity中,可以禁用垃圾回收(GC),但需謹(jǐn)慎使用,并結(jié)合具體場景進(jìn)行管理。
禁用GC的方法
Unity提供了通過腳本控制垃圾回收器行為的API:GarbageCollector.GCMode。
該API支持以下三種模式:
GarbageCollector.Mode.Enabled:默認(rèn)模式,自動觸發(fā)GC。
GarbageCollector.Mode.Manual:禁用自動GC,但可手動調(diào)用System.GC.Collect()或GarbageCollector.CollectIncremental()。
GarbageCollector.Mode.Disabled:完全禁用GC,包括手動調(diào)用也無效。
將GarbageCollector.GCMode設(shè)置為Disabled即可徹底關(guān)閉垃圾回收機(jī)制。
使用場景與最佳實(shí)踐
禁用GC主要用于性能敏感的關(guān)鍵階段,如戰(zhàn)斗、加載、過場動畫等,以避免GC導(dǎo)致的CPU卡頓(GC Spike)。
推薦做法:
1.預(yù)分配內(nèi)存:在進(jìn)入關(guān)鍵階段前,預(yù)先分配所需的所有對象(如對象池、緩存等),確保運(yùn)行時(shí)無新內(nèi)存分配。
2.臨時(shí)禁用GC:進(jìn)入關(guān)鍵階段時(shí)設(shè)置GCMode = Disabled,結(jié)束后立即恢復(fù)為Enabled或Manual。
3.手動清理:恢復(fù)GC后,調(diào)用System.GC.Collect()回收階段性內(nèi)存,防止堆持續(xù)增長。
示例流程:
// 進(jìn)入關(guān)卡前
AllocateLevelResources(); // 預(yù)分配資源
GarbageCollector.GCMode = GarbageCollector.Mode.Disabled;
// 關(guān)卡運(yùn)行中(避免任何new操作)// 關(guān)卡結(jié)束
GarbageCollector.GCMode = GarbageCollector.Mode.Enabled;
System.GC.Collect(); // 回收內(nèi)存
風(fēng)險(xiǎn)與注意事項(xiàng)
內(nèi)存持續(xù)增長:禁用GC后,未引用的對象不會被釋放,若持續(xù)分配將導(dǎo)致內(nèi)存溢出。
必須嚴(yán)格控制內(nèi)存分配:禁止使用字符串拼接、裝箱、Linq、匿名函數(shù)等易產(chǎn)生GC的操作。
推薦結(jié)合0GC編程:使用StringBuilder、對象池、結(jié)構(gòu)體等技術(shù)實(shí)現(xiàn)運(yùn)行時(shí)零托管內(nèi)存分配。
輔助優(yōu)化手段
啟用增量GC(Incremental GC):在Player Settings中開啟Use Incremental GC,將GC工作分?jǐn)偟蕉鄮瑴p少單次停頓時(shí)間。
性能監(jiān)控:使用Profiler或UWA GOT工具監(jiān)控GC Alloc值,定位內(nèi)存分配熱點(diǎn)。
綜上,Unity支持運(yùn)行時(shí)禁用GC,但應(yīng)作為高階優(yōu)化手段,在可控內(nèi)存分配的前提下短期使用,以換取更穩(wěn)定的幀率表現(xiàn)。
From
問答社區(qū)
TOP3:為什么不應(yīng)將游戲邏輯寫在FixedUpdate中?
請問在向別人解釋不要把游戲邏輯放在FixedUpdate,而應(yīng)正常地放在Update里,除了Input事件外,我還能使用哪些理由呢?
A1:FixedUpdate只處理物理相關(guān)的邏輯,Input事件應(yīng)該放Update。
A2:如果卡,F(xiàn)ixedUpdate會在一幀里執(zhí)行多次來追上更新次數(shù),可能導(dǎo)致嚴(yán)重的掉幀和發(fā)熱。若想慢點(diǎn)更新,建議用攜程或者用UniTask。
我需要一些硬性的不能做的理由,目前想到的就只有Input事件會重復(fù)或被跳過。
A3:那Update里面干什么?而且位置更新不放到Update和渲染匹配不上,看著應(yīng)該會有頓的感覺。
A4:FixedUpdate不能動態(tài)鎖幀,全放里面手機(jī)發(fā)熱發(fā)燙耗電也快。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/677b429f682c7e5cd61bf9e4
From
問答社區(qū)
TOP4:InstantiateAsync有什么需要特殊處理的嗎?
請教個(gè)問題,InstantiateAsync有什么需要特殊處理的嗎?我發(fā)現(xiàn)異步實(shí)例化出來的角色,好像丟了蒙皮一樣,Mesh完全不跟著動畫、還有根節(jié)點(diǎn)動,始終以T-pose的形態(tài)呆在固定位置,而且同一個(gè)角色,同步加載是正常的。
這是我這邊的環(huán)境:
![]()
A1:我們在接近你的版本和更高版本試了下,分別復(fù)現(xiàn)了問題和正常加載。查了下可能是類似下面的Unity Bug(異步實(shí)例化相關(guān)的bug有很多),應(yīng)該要升一下版本。
![]()
A2: 的確升級Unity版本后ok了。
A3:沒啥問題,效果也比較好、明顯,總得來說異步實(shí)例化好處多余壞處,我是調(diào)研過了并且項(xiàng)目在使用的。
AsyncInstantiateOperation.GetIntegrationTimeMS() AsyncInstantiateOperation.SetIntegrationTimeMS()可以設(shè)置異步實(shí)例化的間隔時(shí)間,默認(rèn)是2ms,是Unity 2022.3.20新增加的功能。
寫代碼的時(shí)候可以考慮Async/Await,當(dāng)然國際版Unity最新.3.60,國內(nèi)版.3.54。
如果你項(xiàng)目沒啥特殊可以考慮升級到最新,正常來說如果你沒有上線最好到最新或者你得平時(shí)關(guān)注Unity版本發(fā)布日志。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/67ce97913d306f3e9d594e6c
From
問答社區(qū)
TOP5:在Unity轉(zhuǎn)微信小游戲下,如何用Worker實(shí)現(xiàn)多線程?
想用WebWorker計(jì)算Unity里的小球的運(yùn)動軌跡,請問Unity轉(zhuǎn)微信小游戲的情況下,可以用Worker實(shí)現(xiàn)多線程嗎?
A:可以參考官方文檔:https://developers.weixin.qq.com/minigame/dev/api/worker/wx.createWorker.html
功能描述:
創(chuàng)建一個(gè)Worker線程。
參數(shù):
string scriptPath
Worker入口文件的絕對路徑
object options:
可選參數(shù):
屬性:useExperimentalWorker
類型:boolean
默認(rèn)值:false
必填:否
說明:是否使用實(shí)驗(yàn)worker。在iOS下,實(shí)驗(yàn)worker的JS運(yùn)行效率比非實(shí)驗(yàn)Worker提升數(shù)倍,如需在Worker內(nèi)進(jìn)行重度計(jì)算的建議開啟此選項(xiàng)。同時(shí),實(shí)驗(yàn)Worker存在極小概率會在系統(tǒng)資源緊張時(shí)被系統(tǒng)回收,因此建議配合worker.onProcessKilled事件使用,在Worker被回收后可重新創(chuàng)建一個(gè)。
最低版本:2.13.0
返回值
Worker
Worker對象
注意事項(xiàng)
接口使用前需要在game.json(插件為plugin.json)中配置workers字段,表示W(wǎng)orker代碼根目錄。
scriptPath為入口文件的絕對路徑,且不以/開頭。
目前限制最多只能創(chuàng)建一個(gè)Worker,創(chuàng)建下一個(gè)Worker前請先調(diào)用Worker.terminate。
多線程Worker指南(小游戲)。
示例代碼
// 創(chuàng)建普通worker
wx.createWorker('workers/index.js')
function createNewWorker() {
const worker = wx.createWorker('workers/index.js', {
useExperimentalWorker: true
})
// 監(jiān)聽worker被系統(tǒng)回收事件
worker.onProcessKilled(() => {
// 重新創(chuàng)建一個(gè)worker
createNewWorker()
})
}
// 創(chuàng)建實(shí)驗(yàn)worker
createNewWorker()
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/67c559603d306f3e9d594e69
From
問答社區(qū)
TOP6:增量GC機(jī)制,會導(dǎo)致碎片化更嚴(yán)重嗎?
請問增量GC這種頻繁分配與釋放的GC機(jī)制,會導(dǎo)致碎片化更嚴(yán)重嗎?好像介紹增量GC的資料很少,所以有這種疑問。
A:對于碎片的產(chǎn)生,理論上增量GC和普通GC應(yīng)該是沒有什么區(qū)別的,都是標(biāo)記-清除。增量GC只是把GC的工作分幀處理了,控制碎片的占用比例更關(guān)鍵的是要減少大塊臨時(shí)分配。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/684fe482682c7e5cd61bfaae
From
問答社區(qū)
TOP7:為什么場景中沒有剛體更無碰撞事件,但仍有較高物理耗時(shí)?
我有個(gè)疑問:為什么GOT性能報(bào)告和Profiler里看物理模塊耗時(shí)都很高?但其實(shí)這時(shí)候場景里已經(jīng)沒有剛體了,按理說不會發(fā)生碰撞,只有在代碼里用了Raycast判斷子彈命中,后來我把設(shè)置里的物理模擬關(guān)掉,又打了包,物理耗時(shí)確實(shí)降了下來,看子彈還是能正常命中(因?yàn)槭谴a調(diào)的),看粒子里的碰撞也還是能生效。
我不明白的是:之前那么高的物理耗時(shí)是在做什么?可能是什么導(dǎo)致的?是有一些我沒留意到的地方用了物理導(dǎo)致的,還是說Unity機(jī)制如此?(Unity版本2022.3.59)
A:的確, 當(dāng)前Unity版本的機(jī)制就是這樣,很多時(shí)候必須要關(guān)閉掉物理模擬(指把Simulation Mode改成Script)才可以節(jié)省耗時(shí)。具體機(jī)制是場景中只要Static Collider數(shù)量大于0且沒有關(guān)閉物理模擬就會有耗時(shí),和場景中有沒有剛體、有沒有發(fā)生碰撞事件無直接關(guān)聯(lián)。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/684688ea682c7e5cd61bfaa0
From
問答社區(qū)
TOP8:如何用GPU Instancing來優(yōu)化樹木草石重復(fù)模型?
項(xiàng)目場景里的樹木草石重復(fù)模型非常多,在嘗試用GPU Instancing來優(yōu)化。使用的Shader應(yīng)該是SRP Batcher和GPU Instancing都支持的,但是材質(zhì)勾上GPU Instancing后看FrameDebugger里還是走的SRP Batcher,要怎么修改比較好呢?
A:如果 Shader兩個(gè)都兼容,就會優(yōu)先走SRP Batcher的。常規(guī)做法就是把規(guī)劃要用GPU Instancing的物體用別的不走SRP Batcher的Shader;也可以考慮仍然用兩個(gè)都兼容的Shader,但是用MaterialPropertyBlock打斷SRP Batcher,這樣就會順延走GPU Instancing了。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/680dd4d53d306f3e9d594ecc
From
問答社區(qū)
TOP9:如何在運(yùn)行時(shí)獲取硬件信息?
請問怎樣在運(yùn)行時(shí)獲取硬件信息?一般參考其中哪些信息進(jìn)行分級比較合理?
A:一般是用SystemInfo里的一些接口,如圖:
![]()
真機(jī)上輸出效果如圖:
![]()
一般用其中deviceType、deviceName去找對應(yīng)的硬件檔次劃分;或者直接graphicsDeviceName給到的GPU型號進(jìn)行畫質(zhì)分級。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/67f374e1682c7e5cd61bfa35
From
問答社區(qū)
TOP10:如何排查優(yōu)化URP內(nèi)置Shader冗余?
請教一下Shader冗余應(yīng)該怎么查,似乎好幾個(gè)Shader運(yùn)行時(shí)都有兩份?
A: 資源冗余最常見的原因是AssetBundle沒有依賴打包導(dǎo)致的,可以使用UWA的在線AssetBundle檢測進(jìn)行冗余檢測先試試。
測了AssetBundle,確實(shí)有冗余,但AssetBundle冗余的Shader和運(yùn)行時(shí)冗余的Shader好像又不一致。實(shí)際運(yùn)行時(shí)的冗余都是Hidden/Universal Render Pipeline/xxx。這又是為什么呢?
A: 這些是URP的Shader,通常是URP Asset的引用導(dǎo)致的,因?yàn)閁RP Asset會引用這些Shader。而內(nèi)存中出現(xiàn)兩份Shader,說明內(nèi)存中出現(xiàn)了兩個(gè)來源路徑不一樣的URP Asset,通常一份是在PlayerSetting中引用的URP Asset,另外一份可能來自AssetBundle中動態(tài)加載的URP Asset。RendererData里面會引用到PostProcessData,PostProcessData就會引用這些Shader,如果代碼里面動態(tài)加載的 AssetBundle 里面也有這種資源,也會引用一份Shader進(jìn)內(nèi)存,就會造成冗余。
![]()
![]()
![]()
請問這個(gè)怎么處理,直接刪去嗎?
A: 一般只處理內(nèi)存占用比較大的即可,其他的內(nèi)存占用比較小,冗余開銷也不大。比如Hidden/Universal Render Pipeline/Uberpost,需要刪除其中用不到的Keyword來降低占用;又比如Hidden/Universal Render Pipeline/HBAO,看是否確實(shí)要用到,用不到就解除引用。
歡迎大家轉(zhuǎn)至社區(qū)交流:
https://answer.uwa4d.com/question/69245652244ce21ce9ec095c
無論是社區(qū)里開發(fā)者們的互助討論,還是AI基于知識沉淀的快速反饋,核心都是為了讓每一個(gè)技術(shù)難題都有解、每一次踩坑都有回響。本期分享分別來自UWA AI問答和UWA問答社區(qū),希望這些從真實(shí)開發(fā)場景中提煉的經(jīng)驗(yàn),能直接幫你解決當(dāng)下的技術(shù)卡點(diǎn),也讓你在遇到同類問題時(shí),能更高效地找到破局方向。
封面圖來源于網(wǎng)絡(luò)
今天的分享就到這里。生有涯而知無涯,在漫漫的開發(fā)周期中,我們遇到的問題只是冰山一角,UWA社區(qū)愿伴你同行,一起探索分享。歡迎更多的開發(fā)者加入U(xiǎn)WA社區(qū)。
UWA官網(wǎng):www.uwa4d.com
UWA社區(qū):community.uwa4d.com
UWA學(xué)堂:edu.uwa4d.com
點(diǎn)擊下方名片關(guān)注我們,將我設(shè)為星標(biāo),及時(shí)接收小編每日推送哦,性能優(yōu)化不迷路~
近期精彩回顧
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.