GameObject.InstantiateAsync randomly causes runtime to freeze entirely

Hello!
I’m having an issue where eventually, seemingly randomly, InstantiateAsyc will completely freeze the game. The code is for instantiating new locations in the game as you walk around the world.

TLDR:

  • InstantiateAsync calls are running from inside the OnUpdate method of an ISystem
  • They are instantiating prefabs loaded from Addressables
  • The freeze happens between the InstantiateAsync call and the launch of the completed Action

Details:
Location requests are created as you walk around the world and it’s detected that a location needs to be spawned. The freeze seemingly happens randomly, sometimes on the first time it’s loading a location, sometimes later when loading previously loaded/destroyed locations (for ex if you walk back and forth). Currently no Addressable handles are released. It happens both in the Editor and in a build.

The code below has been simplified, stuff that comes from other sources are in <>
When creating a location request, we launch the Addressables loading like so:

                AssetReferenceT<GameObject> locationReference =
                    new AssetReferenceT<GameObject>("Baked/" + <locationID> +".prefab");
                locationReference.LoadAssetAsync();

This location reference is then stored in the locationRequest as locationRequest.prefabReference.
Then, we iterate on the requests:

        foreach (var locationRequest in locationRequests)
        {
            if (!locationRequest.prefabReference.OperationHandle.IsDone ||
                locationRequest.prefabReference.Asset == null)
                continue;
            
                Location location = ((GameObject)locationRequest.prefabReference.Asset).GetComponent<Location>();
                // Make a copy of the local variables used inside the lambda function
                AssetReferenceT<GameObject> prefabReference = locationRequest.prefabReference;
                Location currentLocation = location;
                
                Debug.Log("[InstantiateAsync]: launching instantiation: " + currentLocation.gameObject.name);
                GameObject.InstantiateAsync(location.gameObject, 1, <pivotTransform>, <position>, <rotation>).completed += (operation =>
                {
                    try
                    {
                        AsyncInstantiateOperation asyncOperation = operation as AsyncInstantiateOperation;
                        if (asyncOperation != null && asyncOperation.Result.Length > 0)
                        {
                            <locationStore> = ((GameObject)asyncOperation.Result[0]).GetComponent<Location>();
                            Debug.Log("[InstantiateAsync]: finished instantiation: " + (GameObject)asyncOperation.Result[0]);
                        }
                        else
                        {
                            Debug.LogError("Location async instantiation failed for " + prefabReference.Asset.name);
                        }
                    }
                    catch (Exception e)
                    {
                        Debug.LogError(e);
                        Debug.LogError("Exception happened during Location async instantiation for " + currentLocation.gameObject.name);
                        throw;
                    }
                });
                <removes request from list>
             }

After walking around for a while, the game freezes. In the log, there are no errors, and after multiple “launching instantiation” and “finished instantiation” logs, it freezes after a “launching instantiation”.

Anyone has any idea of why this could be happening?
Any help would be appreciated. Thanks!

Have you been able to narrow it down to a specific object? You could log location.gameObject.name for instance. If it happens to the same object it would seem possible that it runs something in Awake etc that might cause it to spin into an infinite loop.

Try attaching the debugger when it freezes, then set breakpoints inside any loop that may spin out of control.

The only other curious thing is that I would avoid using a lambda as a callback in runtime code (it allocates):

GameObject.InstantiateAsync(location.gameObject, 1, <pivotTransform>, <position>, <rotation>).completed += (operation => ...

Rather keep the object around and use a dedicated method:

var op = GameObject.InstantiateAsync(location.gameObject, 1, <pivotTransform>, <position>, <rotation>);
op.completed += TheCompletionCallback;

I find this also improves code readability quite a bit because it does not intertwine completion code in between the instantiation code (above and below the inline function).

A profile capture could be revealing.

Try move this out of isystem and into systembase. Pretty sure events break in isystem (unreferenced struct) and gc has maybe cleaned up the event.