Unity遊戲執行閃退問題定位與解決(標籤:Oops、crashed、System out of memory、UnityEngine.AssetBundle:LoadAsset_Internal)
阿新 • • 發佈:2021-02-19
技術標籤:Unity3DunityAssetBundleLoadFromFile閃退無效記憶體
文章目錄
一、閃退問題
最近Unity
工程釋出PC
平臺的包,運行遊戲,出現了一個閃退的問題,彈框如下。
根據提示,找到對應的crash
日誌。
開啟output_log.txt
,如下:
... ... The file 'archive:/CAB-350107fab3529178780193de85391267/CAB-350107fab3529178780193de85391267' is corrupted! Remove it and launch unity again! [Position out of bounds!] (Filename: Line: 220) Mismatched serialization in the builtin class 'MonoScript'. (Read 41 bytes but expected 81 bytes) (Filename: Line: 1831) DynamicHeapAllocator allocation probe 1 failed - Could not get memory for large allocation 4227858432. DynamicHeapAllocator allocation probe 2 failed - Could not get memory for large allocation 4227858432. DynamicHeapAllocator allocation probe 3 failed - Could not get memory for large allocation 4227858432. DynamicHeapAllocator allocation probe 4 failed - Could not get memory for large allocation 4227858432. DynamicHeapAllocator out of memory - Could not get memory for large allocation 4227858432! Could not allocate memory: System out of memory! Trying to allocate: 4227858432B with 16 alignment. MemoryLabel: BaseObject Allocation happend at: Line:463 in Memory overview [ ALLOC_DEFAULT ] used: 117172692B | peak: 0B | reserved: 128778716B [ ALLOC_TEMP_JOB ] used: 0B | peak: 0B | reserved: 2097152B [ ALLOC_GFX ] used: 39689080B | peak: 0B | reserved: 44995820B [ ALLOC_CACHEOBJECTS ] used: 1044176B | peak: 0B | reserved: 10485760B [ ALLOC_TYPETREE ] used: 1242064B | peak: 0B | reserved: 4194304B [ ALLOC_PROFILER ] used: 0B | peak: 0B | reserved: 0B [ ALLOC_TEMP_THREAD ] used: 34816B | peak: 0B | reserved: 3244032B Could not allocate memory: System out of memory! Trying to allocate: 4227858432B with 16 alignment. MemoryLabel: BaseObject Allocation happend at: Line:463 in Memory overview [ ALLOC_DEFAULT ] used: 117172692B | peak: 0B | reserved: 128778716B [ ALLOC_TEMP_JOB ] used: 0B | peak: 0B | reserved: 2097152B [ ALLOC_GFX ] used: 39689080B | peak: 0B | reserved: 44995820B [ ALLOC_CACHEOBJECTS ] used: 1044176B | peak: 0B | reserved: 10485760B [ ALLOC_TYPETREE ] used: 1242064B | peak: 0B | reserved: 4194304B [ ALLOC_PROFILER ] used: 0B | peak: 0B | reserved: 0B [ ALLOC_TEMP_THREAD ] used: 34816B | peak: 0B | reserved: 3244032B (Filename: Line: 999) Crash!!! ... ... ========== OUTPUTING STACK TRACE ================== ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9DCD0) 0x00F9DCD0 (SFish) ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9F88C) 0x00F9F88C (SFish) ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9FFAC) 0x00F9FFAC (SFish) 0x0121A644 (SFish) physx::shdfnd::Foundation::getTempAllocFreeTable 0x012157E3 (SFish) physx::shdfnd::Foundation::getTempAllocFreeTable 0x0121666A (SFish) physx::shdfnd::Foundation::getTempAllocFreeTable ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9AFDF) 0x00F9AFDF (SFish) ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9A553) 0x00F9A553 (SFish) ERROR: SymGetSymFromAddr64, GetLastError: '試圖訪問無效的地址。 ' (Address: 00F9A7A9) 0x00F9A7A9 (SFish) 0x0123D395 (SFish) physx::shdfnd::Foundation::getTempAllocFreeTable 0x05F9875A (Mono JIT Code) (wrapper managed-to-native) UnityEngine.AssetBundle:LoadAsset_Internal (string,System.Type) 0x05F9867D (Mono JIT Code) UnityEngine.AssetBundle:LoadAsset (string,System.Type) 0x05F98571 (Mono JIT Code) QRes.AssetBundleMgr:LoadAsset (string,string,bool) 0x05F9834E (Mono JIT Code) QRes.AssetBundleMgr:LoadExternAsset (string) 0x05F9817B (Mono JIT Code) QRes.AssetBundleMgr:LoadAssetFromAssetBundle (string) 0x17746A0F (Mono JIT Code) RbResDestory:Instantiate<object> (string) 0x17746908 (Mono JIT Code) RbResDestory:InstantiateGameObject (int) 0x15C4BB46 (Mono JIT Code) CR_NeHeRunner:Instead (intptr) 0x177A95A5 (Mono JIT Code) (wrapper native-to-managed) CR_NeHeRunner:Instead (intptr) 0x6DF8334E (tolua) lua_lessthan ERROR: SymGetSymFromAddr64, GetLastError: '找不到指定的模組。 ' (Address: 1F293288) ERROR: SymGetModuleInfo64, GetLastError: '動態連結庫(DLL)初始化例程失敗。 ' (Address: 1F293288) 0x1F293288 ((<unknown>)) ========== END OF STACKTRACE =========== **** Crash! ****
二、問題定位與解決
1、結論
根據日誌,得出結論:是在呼叫AssetBundle
的LoadAsset
介面的時候閃退的,訪問了一個無效的記憶體地址。
但,為什麼呢?
2、問題分析
遊戲中做了資源下載的功能:把資源打成AssetBundle
,放在雲端,客戶端運行遊戲時從雲端下載AssetBundle
包到本地,然後從本地中載入資源。
這個流程會存在一個什麼問題呢?
假設我們有個資源包:test.ab
,我們把它放到雲端,客戶端下載到了本地並載入了這個AssetBundle
;接著我們工程中修改了資源,重新打了test.ab
放到雲端,遊戲客戶端在不重啟的情況下又觸發了test.ab
的下載,那麼本地磁碟中的test.ab
AssetBundle
物件與磁碟的AssetBundle
檔案不對應了,如果此時呼叫LoadAsset
介面就會出現無效記憶體訪問,導致閃退。
這又引出了另一個疑問,我們載入AssetBundle
的時候,程式碼如下:
AssetBundle ab = AssetBundle.LoadFromFile(ab_path);
我們已經通過AssetBundle.LoadFromFile
載入了AssetBundle
到記憶體中,為什麼此時刪除或者覆蓋磁碟中的AssetBundle
會影響記憶體中的AssetBundle
呢?
事實上,AssetBundle.LoadFromFile
LoadAsset
接口才會真正把資源從磁碟中讀取到記憶體中,並且只讀取對應的Asset
;如果想要讀取AssetBundle
中所有的Asset
,可以使用LoadAllAssets
或LoadAllAssetsAsync
載入所有Asset
。當我們使用
LoadAsset
讀取了某個資源到記憶體中後,即使磁碟中的AssetBundle
刪除或者被覆蓋成其他檔案,都不會再影響記憶體中再次LoadAsset
這個資源了,也就是說,記憶體中的AssetBundle
物件自身是會有一層快取的,第一次呼叫LoadAsset
時是從磁碟中的AssetBundle
檔案中讀取資源,再次呼叫LoadAsset
相同資源是,直接從記憶體中的AssetBundle
物件快取中讀取了。
3、解決辦法
根據分析,解決辦法就是首次載入AssetBundle
物件後就執行LoadAllAssetsAsync
載入所有Asset
,即可避免因為資源覆蓋下載導致LoadAsset
出現無效記憶體訪問。