(如何)可以在Unity 2019上强制进行垃圾收集并等待未完成的终结器?

时间:2019-06-29 08:52:24

标签: c# unit-testing unity3d garbage-collection

我的团队正在使用C#开发Unity项目。在某些地方,我们称为System.GC.Collect()System.GC.WaitForPendingFinalizers()(仅在测试中,而不在生产代码中。为什么这样做与我的问题无关,但如果有人感兴趣,请在下面说明)。过去在Unity 2018.1上可以正常工作,但是自从我们升级到Unity 2019.1以来似乎已经停止一致地工作(即有时似乎可以工作,但并非总是如此)。我们在macOS上使用Mono,并尝试了启用和禁用增量GC的新引入的功能,而没有明显的差异。

有人知道在这些Unity版本之间有什么改变的原因吗?有人知道强制垃圾收集并等待在Unity 2019上起作用的未决终结器的其他方法吗?

我无济于事:多次调用GC.Collect()GC.WaitForPendingFinalizers(),在调用它们之后睡眠很长时间,分配了大量的内存(我想还不够大,但是再次,我也不想推动它。)

注意:我们依次呼叫Collect()WaitForPendingFinalizers();我不知道这两者中的哪一个是未真正实现预期效果的(或者是否两者兼而有之),因为只有两者结合才能达到我们正在测试的效果。有助于缩小问题范围的想法也将受到赞赏。

我们为什么需要这个

我们有一类,根据情况的不同,它们的实例可能寿命很长,并且在其生命周期中的某个时刻存储了大量数据,以后不再需要这些数据。为了释放内存,当不再需要数据时,将引用该数据的字段分配为null

我没有理由认为这不能正常工作,但是问题在于此功能的单元测试,该功能过去在Unity 2018.1上可以正常工作,但是自从我们将项目迁移到以下版本以来一直断断续续地失败Unity 2019.1。

示例代码

以下是一个(大大简化了!)的示例,该示例演示了此问题:该测试始终在Unity 2018.1上通过,但在Unity 2019.1上未通过。我试图将其最小化。我不知道为什么,但是如果不使用List(在一个单一的object而不是在Unity 2019.1上始终通过的List<object>的相似版本)下,我就无法使其工作。 -这可能是问题的一部分,也可能不是问题的一部分。

using System;
using System.Collections.Generic;

using NUnit.Framework;

public class MyClass {
    List<object> someData = new List<object>();

    public void RegisterData(object data) => someData.Add(data);

    public void ForgetData() => someData = null;
}

[TestFixture]
public class MyClassTest {
    class ObservablyFinalizable {
        readonly Action onFinalize;

        public ObservablyFinalizable(Action onFinalize) {
            this.onFinalize = onFinalize;
        }

        ~ObservablyFinalizable() {
            onFinalize();
        }
    }

    MyClass instance;
    bool isFinalized;

    [SetUp]
    public void SetUp() {
        instance = new MyClass();
        isFinalized = false;
    }

    [Test]
    public void ShouldForgetData() {
        WhenRegisteringObservablyFinalizableData();
        WhenForgettingData();
        WhenGarbageCollected();

        ThenFinalized();
    }

    void WhenRegisteringObservablyFinalizableData() =>
        instance.RegisterData(new ObservablyFinalizable(() => isFinalized = true));

    void WhenForgettingData() => instance.ForgetData();

    static void WhenGarbageCollected() {
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

    void ThenFinalized() => Assert.That(isFinalized);
}

0 个答案:

没有答案