-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
C#: Possible deadlock during GD.Load()
if the garbage collector disposes a script while the loader tries to register one
#87405
Comments
Is it maybe possible to reproduce this bug more consistently by calling GC.Collect() in various spots in different threads to attempt forcing garbage collection to run during GD.Load()? |
It looks like I'm experiencing exactly this issue in my project. I'm making city building game, and once game is loaded (with dynamic chunks and objects), it permanently freezes game 80-90% of the time if I try to open building's menu (music is playing in background, but window is completely non-responsive. no errors are printed in console even with --verbose editor flag). It also randomly freezes during loading of menus during playing (with extremely low chance, like once per week). I found this issue by searching for |
Yes, that sounds very similar. For me, the deadlock is very rare in general but very consistent when loading a specific savefile. By the way, for my case, I was able to work around this for the moment by doing |
Thank you for sharing workaround! For anyone who would stumble upon this issue I would also suggest to wrap
|
Tested versions
v4.2.1.stable.mono.official [b09f793]
System information
Godot v4.2.1.stable.mono - Windows 10.0.19045 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 2070 (NVIDIA; 31.0.15.4633) - Intel(R) Core(TM) i7-10875H CPU @ 2.30GHz (16 Threads)
Issue description
There's probably no good way to reproduce this reliably, so I don't know how much value this report has, but there appears to be a possible deadlock in how C# scripts are created and disposed.
When loading a scene via
GD.Load<PackedScene>()
, there seems to be a chance that the .NET Garbage Collector running on a separate thread disposes a resource containing a script while the loading code on the main thread tries to register a new script for the new scene. With a bit of unlucky timing, this can lead to the garbage collector waiting for the main thread to release the_scriptTypeBiMap.ReadWriteLock
lock while the main thread is waiting for the garbage collector to release theCSharpLanguage::get_singleton()->script_instances_mutex
mutex, which deadlocks the game.Here's how this might look like:
Main Thread
I can't look into the C++ code from here, but it's presumably waiting on the
CSharpLanguage::get_singleton()->script_instances_mutex
mutex atgodot/modules/mono/csharp_script.cpp
Lines 2816 to 2825 in b09f793
after having taken the
_scriptTypeBiMap.ReadWriteLock
lock atgodot/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
Lines 454 to 468 in b09f793
GC Finalizer Thread
Waiting on the
_scriptTypeBiMap.ReadWriteLock
atgodot/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
Lines 524 to 538 in b09f793
after presumably having taken the
CSharpLanguage::get_singleton()->script_instances_mutex
mutex atgodot/modules/mono/csharp_script.cpp
Lines 2827 to 2836 in b09f793
Notes
From the
#ifdef
s it seems that this only affects DEBUG builds. There apparently is a way to disable background garbage collection in .NET, although performance-wise, it may be preferable to find a way to make script creation and disposal thread-safe. At first glance, it may not be necessary for~CSharpScript()
to hold on to the mutex while callingScriptManagerBridge_RemoveScriptBridge()
.Steps to reproduce
None, unfortunately. Requires a project that uses C# scripts, certain circumstances that trigger a garbage collection during a
GD.Load()
, and possibly some unlucky timing. Hopefully, the problem can be diagnosed based on the code and the stack traces.Minimal reproduction project (MRP)
N/A
The text was updated successfully, but these errors were encountered: