Premature Garbage Collection

I have a class, ControlFlagBehavior, which is the functional backend of another class, ControlFlag. For some reason, this class is exhibiting some very odd behavior. This is the class definition, with nothing changed or stripped out:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public class ControlFlagBehavior : MonoBehaviour
{
    public static ControlFlagBehavior Create(ControlFlag flag)
    {
        if (flag == null) throw new ArgumentNullException("flag");

        var raq = Service.Provider.Current.GetService<ResourceAcquisitionService>();
        var template = raq.GetPrefab("Ornaments/ControlFlagTemplate");
        var obj = (GameObject)Instantiate(template);
        var beh = obj.GetComponent<ControlFlagBehavior>();
        beh.flag = flag;
        return beh;
    }

    private ControlFlag flag;
    public ControlFlag ControlFlag
    {
        get
        {
            return flag;
        }
    }
    public GameController GameController
    {
        get
        {
            return flag.GameController;
        }
    }

    public virtual void Start()
    {
    }
    public virtual void Update()
    {
        float tlx, tly, tlz;
        if (flag == null)
        {
            Debug.LogWarning("Flag null! Deleting gameObject...");
            GameObject.Destroy(gameObject);
            return;
        }
        flag.GetOrnamentLocation(out tlx, out tly, out tlz);

        var pos = transform.position;
        pos.x = tlx;
        pos.y = tly + .03f;
        pos.z = tlz;
        transform.position = pos;
    }
}

As you can see, flag is assigned only once, and it cannot be null. If flag is ever detected to be null, then an error message is logged and the GameObject and behavior are destroyed.

When I run the game, this all works fine. The prefab is found and instantiated, and the Update function correctly positions the GameObject. If you wait, however, then eventually "Flag null! Deleting gameObject..." is logged, and all of the ControlFlagTemplatess that were instantiated are deleted at the same time.

I have no idea why this is happening. According to the rules of the C# language, flag should be impossible to modify outside of the object. The only guess I can make is that some bug in the Unity engine or in the Mono garbage collector is prematurely collecting the ControlFlag object, despite the fact that it is referenced in the behavior (and, incidentally, in a few other places.)

A few notes: I have no untrusted code. I have not done anything with reflection. When I have multiple ControlFlag objects (each with their own ControlFlagBehavior) they are all set to null during the same frame.

So, why is this happening? More importantly, how do I fix it?

Thanks.

I guess that you are testing inside the editor, you edit your scripts in the background and switch back to Unity. Whenever Unity reimports / recompiles a script it has to:

  • serialize the scene
  • Shutdown the mono runtime / unload the script assemblies
  • recompile the script assemblies
  • deserialize the scene to restore the previous state

That means everything that isn’t serialized (private variables and static variables) is lost when this happens.

I’m not sure if the same could happen at a scene change with objects marked with DontDestroyOnLoad. In all my projects i never load a level since most stuff is procedurally generated :wink:

edit
So in conclusion: If you want to be able to edit scripts while you test in the editor you have to store everything in serializable variables. That means if you use singletons they need to be able to restore their static variable (the easiest way is FincObjectOfType). All private variables need to be marked with SerializeField (and HideInInspector if you don’t want it to be visible in the inspector).

Keep in mind that Unity can’t serialize all types!! I’ve given up this feature a long time ago. If i change something i stop the game and restart it.