Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ForceUnloadAllScenes on Application Quit causes crash on Android #301

Closed
FedericoLaGreca opened this issue Jul 13, 2017 · 9 comments
Closed

Comments

@FedericoLaGreca
Copy link

Hello,
We noticed in our project that this code in ProjectKernel.cs

public void OnApplicationQuit()
 {
     ForceUnloadAllScenes(true);

     Assert.That(!IsDestroyed);
     GameObject.DestroyImmediate(this.gameObject);
     Assert.That(IsDestroyed);
 }

causes a native crash on some Android devices on app quit (happens at least on Unity 5.6.2 and Unity 2017). The crash is a classic Unity SIGSEGV with the following code addresses:

#00  pc 00125a84  /data/app-lib/<app-pkg>-15/libunity.so
#01  pc 003159d4  /data/app-lib/<app-pkg>-15/libunity.so
#02  pc 0031ae94  /data/app-lib/<app-pkg>-15/libunity.so
#03  pc 0031c06c  /data/app-lib/<app-pkg>-15/libunity.so
#04  pc 005ed508  /data/app-lib/<app-pkg>-15/libunity.so
#05  pc 005ef33c  /data/app-lib/<app-pkg>-15/libunity.so
#06  pc 00020e0c  /system/lib/libdvm.so (dvmPlatformInvoke+112)
#07  pc 00051aaf  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+398)
#08  pc 0002a2a0  /system/lib/libdvm.so
#09  pc 00031750  /system/lib/libdvm.so (dvmMterpStd(Thread*)+76)
#10  pc 0002ede8  /system/lib/libdvm.so (dvmInterpret(Thread*, Method const*, JValue*)+184)
#11  pc 00063f15  /system/lib/libdvm.so (dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)+336)
#12  pc 00063f39  /system/lib/libdvm.so (dvmCallMethod(Thread*, Method const*, Object*, JValue*, ...)+20)
#13  pc 00058c0b  /system/lib/libdvm.so
#14  pc 0000d288  /system/lib/libc.so (__thread_entry+72)
#15  pc 0000d420  /system/lib/libc.so (pthread_create+240)

The libunity.so calls point to this stacktrace:

GameObject::SendMessageAny(MessageIdentifier const&, MessageData&)
SendMessageToEveryone(MessageIdentifier const&, MessageData)
NotifyPlayerQuit(bool)
PlayerCleanup(bool)
UnityDeinitApplication()
nativeDone(_JNIEnv*, _jobject*)

Removing the OnApplicationQuit solves the issue for us, what is the reason for unloading scenes when the application is quitting anyway?

@svermeulen
Copy link

The comment above ProjectKernel.OnApplicationQuit explains the reasoning. Basically, when a scene is unloaded, or the application is closed, Unity destroys all the game objects in an unpredictable order. Also, OnDestroy does not use Unity's Script Execution Order, so there's no way to control that either, except by exploiting the fact that Unity does at least destroy the root level transforms first before children.

However, if you do need a predictable destruction order, you can use Zenject's IDisposable bindings. You can also use this with MonoBehaviours in addition to normal C# classes, as long as you also check "ParentNewObjectsUnderRoot" on each scene context (to ensure the SceneContext is destroyed before children since as mentioned above Unity will at least destroy game objects top-down).

However, in order to get this same predictable destruction order to work when using Unity's multi-scene editing, we have to explicitly delete each scene context in reverse order that they were loaded. This is because Unity also doesn't unload scenes in any predictable order either.

If you aren't using multiple scenes, or if you don't care about predictable destruction order, then there's no risk in removing that behaviour from ProjectKernel

@FedericoLaGreca
Copy link
Author

Thanks,

I forgot about that comment, sorry.
We do have multiple scenes, but I don't see a reason why we would care about the objects destruction order in our project, so we'll keep the code commented for now and check if we'll ever need it.

My guess is that the native side of Unity is trying to send a message to a GameObject that was destroyed by the scenes unload call. Also, Unity suggests to not use DestroyImmediate outside the editor, maybe the problem's there?

@svermeulen
Copy link

Good point. Can you try changing to Destroy and seeing if that fixes it?

@FedericoLaGreca
Copy link
Author

I'll try tomorrow morning and let you know, thanks

@svermeulen
Copy link

I have a feeling that we were using DestroyImmediate for a reason there though. I am guessing that Unity recommends against it so that they can destroy objects in batches at the end of the frame, so Destroy probably just queues it to be destroyed. In this case though it is probably already queued for destroy so that might not actually have any effect and defeat the purpose of the whole thing

@FedericoLaGreca
Copy link
Author

FedericoLaGreca commented Jul 14, 2017

Hello,
From some tests it looks like switching from DestroyImmediate to Destroy fixes the issue, you just need to check if you really used DestroyImmediate for a reason ;)

@svermeulen
Copy link

Ok thanks for letting me know - I will take a look

@Fido789
Copy link

Fido789 commented Dec 7, 2017

This piece of code within OnApplicationQuit() method caused many crashes of my Unity editor when exiting play mode. I can confirm that replacing by Destroy fixes the issue, but with error

ZenjectException: Assert hit! ModestTree.Assert.That (Boolean condition) (at Assets/Plugins/Zenject/Source/Internal/Assert.cs:14) Zenject.ProjectKernel.OnApplicationQuit () (at Assets/Plugins/Zenject/Source/Runtime/Kernels/ProjectKernel.cs:40)

Anyways, I am really happy to have it solved, it was really, and I mean really annoying.

@svermeulen
Copy link

svermeulen commented Jul 8, 2018

Fixed by making this behaviour optional and off by default (togglable in zenject settings)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants