Game crashes randomly at GarbageCollectSharedAssets

,

Hello guys!

I’m having a weird issue when running my game on iOS:
Some minutes after running the game freezes and throws a crash. Usually, this happens when loading a scene, but sometimes it crashes during gameplay.

This is the stack trace I get in Crashlytics, it looks like the trace people are getting in this old thread :

Crashed: com.apple.main-thread
0  UnityFramework                 0x1724360 il2cpp::vm::LivenessState::AddProcessObject(Il2CppObject*, il2cpp::vm::LivenessState*) + 44
1  UnityFramework                 0x17240b8 il2cpp::vm::LivenessState::TraverseGCDescriptor(Il2CppObject*, il2cpp::vm::LivenessState*) + 60
2  UnityFramework                 0x1723f28 il2cpp::vm::LivenessState::TraverseObjects() + 116
3  UnityFramework                 0x172469c il2cpp::vm::Liveness::FromStatics(void*) + 348
4  UnityFramework                 0x6dc840 GarbageCollectSharedAssets(bool, bool) + 1644
5  UnityFramework                 0x7056e0 UnloadUnusedAssetsOperation::IntegrateMainThread() + 28
6  UnityFramework                 0x70478c PreloadManager::UpdatePreloadingSingleStep(PreloadManager::UpdatePreloadingFlags, int) + 228
7  UnityFramework                 0x705248 PreloadManager::UpdatePreloading() + 276
8  UnityFramework                 0x6e6f20 ExecutePlayerLoop(NativePlayerLoopSystem*) + 100
9  UnityFramework                 0x6e6f60 ExecutePlayerLoop(NativePlayerLoopSystem*) + 164
10 UnityFramework                 0x6e7218 PlayerLoop() + 280
11 UnityFramework                 0xdc848c UnityPlayerLoopImpl(bool) + 112
12 UnityFramework                 0x17680 UnityRepaint + 40
13 QuartzCore                     0x29328 CA::smile:isplay::smile:isplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 820
14 QuartzCore                     0x146e68 CA::smile:isplay::smile:isplayLink::dispatch_deferred_display_links(unsigned int) + 380
15 UIKitCore                      0x64dd94 _UIUpdateSequenceRun + 84
16 UIKitCore                      0xcb2894 schedulerStepScheduledMainSection + 144
17 UIKitCore                      0xcb1df0 runloopSourceCallback + 92
18 CoreFoundation                 0xd3128 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
19 CoreFoundation                 0xdf7b4 __CFRunLoopDoSource0 + 176
20 CoreFoundation                 0x645e8 __CFRunLoopDoSources0 + 244
21 CoreFoundation                 0x7a0d4 __CFRunLoopRun + 828
22 CoreFoundation                 0x7f3ec CFRunLoopRunSpecific + 612
23 GraphicsServices               0x135c GSEventRunModal + 164
24 UIKitCore                      0x39cf58 -[UIApplication _run] + 888
25 UIKitCore                      0x39cbbc UIApplicationMain + 340
26 UnityFramework                 0x172b4 -[UnityFramework runUIApplicationMainWithArgc:argv:] + 92
27 Hero's Quest                   0x57d4 main + 28 (main.mm:28)
28 ???                            0x1c02f4dec (Missing)

It looks like the game is crashing when the garbage collector is working, that would explain why it crashes when loading scenes.

The game uses Addressables for all assets and scenes, I’m on Unity 2022.3.8f1, IL2CPP.
What I’ve tried so far without any success:

  • Disabling incremental GC
  • Temporarily removing any JSON serialization/deserialization
  • Commenting out all addressable “Release” calls
  • Building with minimal scenes (5 instead of all 60+)

I’ve tried everything I could and nothing changes anything, the game runs fine, loads scenes, and does everything as expected but out of nowhere it freezes, doesn’t crash to the home screen but logs the crash to Firebase. When the game freezes I can hear the audio chipping out.

Is there anything else I could try? Is this a known ting with 2022.3.x?

This is usually an indication of some memory corruption in a managed object allocated from the heap. The code in il2cpp::vm::LivenessState traverses the managed heap, building a graph of object references and trying to find assets that are no longer used and can be collected. It is not usually the cause of these problems, but it does often discover them.

Usually the causes fall into one of two camps:

  • Some code in your project is using unsafe C# code or native code that touches managed objects somehow, and causes this corruption.
  • Some code in Unity is corrupting a managed object

If you inspect your code and don’t find anything in camp (1), can you file a bug report with a project that causes this? WE can investigate it, and hopefully track down the code in Unity causing this, if that is the problem.

If you want to report a bug, instructions about how to do that are here: Unity QA: Building quality with passion

The issue started happening after upgrading from 2021 lts to 2022 lts and the introduction of the addressable a package. There are no “unsafe” keyword in the entire project, nor am I messing with managed code. I tried to reproduce with an empty project without any success, it might be a mix of too many addressables groups or the mix of packages the game uses. Sadly I don’t feel comfortable with sending my project.

When running from Xcode and looking at the logs every crash is happening seconds after an asset is loaded/unloaded inside an async function. I do lots of load/release calls since all spritesheets are in “pack separate” asset groups and loaded on demand.
Android is crashing in the same way, I just can’t confirm if the stack trace is the same since I’m not uploading debug symbols to firebase on development builds, but by the logcat I can see it’s happening at the same location as iOS.

Said that, I noticed the crashes stopped happening once I set stripping level to minimal (from high), low still crashes. Never had any issues with high stripping level before 2022+addressables. I’ll have to accept a higher bundle size until this can be fixed.

Interesting - I would not expect the stripping level to impact behavior like this. Can you submit this project with a bug report? It does sound like a problem on the Unity side. We definitely want to investigate and correct it.

Hi !

Is there any news on this ? I’m facing pretty much the same problem using Unity 2022.3.0, and setting the stripped level to minimal doesn’t seems to fix anything.

Note that i’m not on iOS (but the platform is NDA restricted), and that I don’t have any unsafe code in the entire project.

I don’t believe we received a bug report on this, and we were not able to track it down otherwise. If you can submit a bug report, that would be really helpful.

I’ve just started getting this as well. Weirdly, when building the Xcode project on one machine the issue occurs as described above. However, zipping up that Xcode project, copying it another machine and then building/running there results in the issue disappearing. What’s that all about?!

I should mention that I’m seeing this on macOS, iOS and Android projects.

Ben

Update: taking the built macOS binary built on the problematic machine and running it on the other machine results in no issue. So perhaps this is a timing thing? The second machine is faster than the first, in my case…

Ben

Mine turned out to be loading a save game using a BinaryFormatter where the class layout had changed since the file was serialised. That explains why it worked on one machine but not the other. I’m not sure why Unity decided to die on its butt when attempting to do this (rather than throwing exceptions for me to handle), but that’s what was causing it. Specifically the call to BinaryFormatter.Deserialize().

Ben

I’m glad that you sorted this out! Unfortunately BinaryFormatter is not great overall, with cases like this not uncommon. If you have an option to use a different serialization format, I would recommend moving away from BinaryFormatter.

Hey Josh,

Thanks for getting back to me. Well I need my classes serialised into bytes for console support. Any advice on an alternative to BinaryFormatter? It seems that there are a few options, but all seem more complex and (to my mind) potentially more error prone that the “back to basics” BinaryFormatter. Would appreciate your insight if you have anything to suggest…

Thanks!

Ben

For anyone else who comes across my problem: I solved it by implementing ISerializable. I made a constructor like this:

protected MySaveGame(SerializationInfo info, StreamingContext context) { ... }

And inside that I used info.GetEnumerator() to loop over each SerializationInfo object until current.Name == “someProperty”. Then used current.ObjectType to see if it was the new Type or the old one. If it was the former I just assigned it directly to someProperty; if the latter then I wrote some code to construct the new Type from the old one.

Note: you also need to write GetObjectData(SerializationInfo info, StreamingContext context) if you implement ISerializable, which is kind of a pain…

Ben

Sorry, I don’t have a great solution here. I know from the many bug reports we have seen around BinaryFormatter that it can be tricky, but I don’t know enough about the solution space to suggest an alternative.

No worries. Appreciate you getting back to me, thanks!

Ben

Hi, we’re seeing something very similar in 2021.3.9f1, which is affecting 99% iOS 17 users. I’ve double checked the code and don’t believe we’re using a BinaryFormatter anywhere.

0
UnityFramework
Class.cpp - Line 833
il2cpp::vm::Class::IsValuetype(Il2CppClass const*) + 833
1
UnityFramework
Liveness.cpp - Line 262
il2cpp::vm::LivenessState::TraverseObjects() + 262
2
UnityFramework
Liveness.cpp - Line 439
il2cpp::vm::LivenessState::TraverseArray(Il2CppArray*, il2cpp::vm::LivenessState*) + 439
3
UnityFramework
Liveness.cpp - Line 262
il2cpp::vm::LivenessState::TraverseObjects() + 262
4
UnityFramework
Liveness.cpp - Line 439
il2cpp::vm::LivenessState::TraverseArray(Il2CppArray*, il2cpp::vm::LivenessState*) + 439
5
UnityFramework
Liveness.cpp - Line 262
il2cpp::vm::LivenessState::TraverseObjects() + 262
6
UnityFramework
Liveness.cpp - Line 439
il2cpp::vm::LivenessState::TraverseArray(Il2CppArray*, il2cpp::vm::LivenessState*) + 439
7
UnityFramework
Liveness.cpp - Line 262
il2cpp::vm::LivenessState::TraverseObjects() + 262
8
UnityFramework
Liveness.cpp - Line 587
il2cpp::vm::Liveness::FromStatics(void*) + 587
9
UnityFramework
Time.h - Line 30
GarbageCollectSharedAssets(bool, bool) + 30
10
UnityFramework
UnloadUnusedAssetsOperation.cpp - Line 48
UnloadUnusedAssetsOperation::IntegrateMainThread() + 48
11
UnityFramework
PreloadManager.cpp - Line 402
PreloadManager::UpdatePreloadingSingleStep(PreloadManager::UpdatePreloadingFlags, int) + 402
12
UnityFramework
PreloadManager.cpp - Line 554
PreloadManager::UpdatePreloading() + 554
13
UnityFramework
PlayerLoop.cpp - Line 383
ExecutePlayerLoop(NativePlayerLoopSystem*) + 383
14
UnityFramework
PlayerLoop.cpp - Line 407
ExecutePlayerLoop(NativePlayerLoopSystem*) + 407
15
UnityFramework
PlayerLoop.cpp - Line 514
PlayerLoop() + 514

Update: The issue was an improper use of GameCenter, moving callbacks back and forth between threads and a custom MainThreadDispatcher we have that runs stuff on the main thread. Be careful with this kind of thing.