Search Unity

Garbage collection is not happening in tests

Discussion in 'Scripting' started by Flying_Banana, Jun 28, 2019.

  1. Flying_Banana

    Flying_Banana

    Joined:
    Jun 19, 2019
    Posts:
    29
    I wrote a script that implements the weak event pattern. To test out whether it is working, I wrote a Unity test. The test requires the garbage collector to force free an object, but no matter what I do I can't get GC to collect it.

    Code (CSharp):
    1. using System;
    2. using NUnit.Framework;
    3.  
    4. public class GCTest {
    5.   [Test]
    6.   public void WhenCollectedThenWeakReferenceIsDead() {
    7.     object o = new object();
    8.     WeakReference weakO = new WeakReference(o);
    9.     o = null;
    10.     GC.Collect(2, GCCollectionMode.Forced, /* isBlocking */ true);
    11.     Assert.IsFalse(weakO.IsAlive);
    12.   }
    13. }
    This fails.

    Well, perhaps it is not immediate. I placed a slightly modified script into a MonoBehaviour and added to a test scene and ran it.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3.  
    4. public class GCTest : MonoBehaviour {
    5.   WeakReference weakO;
    6.  
    7.   void Start() {
    8.     object o = new object();
    9.     WeakReference weakO = new WeakReference(o);
    10.     o = null;
    11.     GC.Collect(2, GCCollectionMode.Forced, /* isBlocking */ true);
    12.   }
    13.  
    14.   void Update() {
    15.     if (weakO.IsAlive) {
    16.       Debug.Log("Still alive!");
    17.     } else {
    18.       Debug.Log("Now dead!");
    19.     }
    20.   }
    21. }
    And it appears that the object is now being collected about one second after play starts.

    Well it's not great that I can't force GC to collect straight away even though I set it to blocking, but I can deal with that. I proceeded to convert my test to run in Play Mode.

    Code (CSharp):
    1. using System;
    2. using NUnit.Framework;
    3.  
    4. public class GCTest {
    5.   WeakReference weakO;
    6.  
    7.   [UnityTest]
    8.   public void WhenCollectedThenWeakReferenceIsDead() {
    9.     object o = new object();
    10.     weakO = new WeakReference(o);
    11.     o = null;
    12.     GC.Collect(2, GCCollectionMode.Forced, /* isBlocking */ true);
    13.  
    14.     while (weakO.IsAlive) {
    15.       Debug.Log("Still alive!");
    16.       yield return new WaitForFixedUpdate();
    17.     }
    18.  
    19.     Debug.Log("Now dead!");
    20.   }
    21. }
    This time GC failed me again. weakO remained alive after test timed out (30 seconds).

    I'm not quite sure what's happening behind the scene here. Does GC.Collect() just not work in Unity tests?