文章目錄
一、閃退問題
最近Unity工程發(fā)布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::getTempAllocFreeTableERROR: 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_lessthanERROR: SymGetSymFromAddr64, GetLastError: '找不到指定的模塊。' (Address: 1F293288)ERROR: SymGetModuleInfo64, GetLastError: '動態(tài)鏈接庫(DLL)初始化例程失敗。' (Address: 1F293288)
0x1F293288 ((<unknown>)) ========== END OF STACKTRACE ===========**** Crash! ****
二、問題定位與解決
1、結論
根據日志,得出結論:是在調用AssetBundle的LoadAsset接口的時候閃退的,訪問了一個無效的內存地址。
但,為什么呢?
2、問題分析
游戲中做了資源下載的功能:把資源打成AssetBundle,放在云端,客戶端運行游戲時從云端下載AssetBundle包到本地,然后從本地中加載資源。
這個流程會存在一個什么問題呢?
假設我們有個資源包:test.ab,我們把它放到云端,客戶端下載到了本地并加載了這個AssetBundle;接著我們工程中修改了資源,重新打了test.ab放到云端,游戲客戶端在不重啟的情況下又觸發(fā)了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對象后就執(zhí)行LoadAllAssetsAsync加載所有Asset,即可避免因為資源覆蓋下載導致LoadAsset出現無效內存訪問。
總結
以上是生活随笔為你收集整理的Unity游戏运行闪退问题定位与解决(标签:Oops、crashed、System out of memory、UnityEngine.AssetBundle:LoadAsset_Internal)的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。