我的团队正在使用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);
}