.net 在WeakReference.IsLive()变为false之前,在完全垃圾收集之后是否有延迟?

.net 在WeakReference.IsLive()变为false之前,在完全垃圾收集之后是否有延迟?,.net,unit-testing,garbage-collection,dispose,.net,Unit Testing,Garbage Collection,Dispose,我已经编写了一个单元测试来确认我的类上的“Dispose”没有取消所有事件的钩子,并处理一个引用该对象的计时器 然而,有时WeakReference.IsLive返回true,而我希望它返回false 那么,在更新WeakReference.IsLive之前,完整GC之后是否有延迟 如果不是的话,你能想出其他能给我带来不可重复结果的方法吗 WeakReference weekJobWatchDog = new WeakReference(jobWatchDog); jobWatchDog = n

我已经编写了一个单元测试来确认我的类上的“Dispose”没有取消所有事件的钩子,并处理一个引用该对象的计时器

然而,有时WeakReference.IsLive返回true,而我希望它返回false

那么,在更新WeakReference.IsLive之前,完整GC之后是否有延迟

如果不是的话,你能想出其他能给我带来不可重复结果的方法吗

WeakReference weekJobWatchDog = new WeakReference(jobWatchDog);
jobWatchDog = null;

// not collected before Dispose called due to timer and events etc
GC.Collect(); GC.Collect();
Assert.IsTrue(weekJobWatchDog.IsAlive);

((IDisposable)weekJobWatchDog.Target).Dispose();

// is now collected as Dispose unlocked all events and dispoed the timer
GC.Collect(); GC.Collect();
Assert.IsFalse(weekJobWatchDog.IsAlive); // sometimes this fails, about 1 in 4 runs
另请参见,了解相关但不同的问题

有一个解决方案,包括调用GC.WaitForPendingFinalizers,但是,我不想调用GC.WaitForPendingFinalizers,因为我希望证明我的dispose有效,如果它有效,就不需要运行任何终结器。

因为Collect方法没有阻塞,所以我猜测——这只是猜测——GC没有在您测试IsAlive时收集对象

别忘了

我认为解决方案可能必须是对WaitForPendingFinalizers之类的东西的阻塞调用,即使您自己没有任何终结器可以等待。我不确定您是否可以使用其他合适的阻塞方法。

因为Collect方法不阻塞,所以我猜测-这只是猜测-GC没有在您测试IsAlive时收集对象

别忘了

我认为解决方案可能必须是对WaitForPendingFinalizers之类的东西的阻塞调用,即使您自己没有任何终结器可以等待。我不确定是否有其他合适的阻塞方法可以替代。

这就是我遇到的问题:

在System.Timers.Timer上调用Dispose时,它可能会在Win32计时器销毁之前返回。因此,在非托管空间中仍然有一个“根”,使计时器保持活动状态。当时有一个事件处理程序使我的对象保持活动状态

由于这是非常及时的,大部分时间定时器会得到GCed,我的对象也会得到GCed。然而,有时会说十分之一的计时器会保持活动状态,我的对象也会保持活动状态

短时间的睡眠会使我的测试在100%的时间内通过,因此在处理计时器之前取消计时器上的事件挂钩,因此计时器无法使我的对象保持活动状态

另请参见

这是我遇到的问题:

在System.Timers.Timer上调用Dispose时,它可能会在Win32计时器销毁之前返回。因此,在非托管空间中仍然有一个“根”,使计时器保持活动状态。当时有一个事件处理程序使我的对象保持活动状态

由于这是非常及时的,大部分时间定时器会得到GCed,我的对象也会得到GCed。然而,有时会说十分之一的计时器会保持活动状态,我的对象也会保持活动状态

短时间的睡眠会使我的测试在100%的时间内通过,因此在处理计时器之前取消计时器上的事件挂钩,因此计时器无法使我的对象保持活动状态


另请参见

如果WeakReference的IsLive属性返回false,这意味着该引用现在是并且将永远是kaput,并且无需检查其值。如果它返回true,这意味着引用可能是活动的,但只有在尝试将其值捕获到强引用中时才能真正知道。一个人不应该依赖于一个弱引用在任何特定的及时性程度上无效,也不应该接受它的价值,除非他真的对它感兴趣。如果一个人正在做一些事情,比如清理weakreference列表,删除那些已经死亡的,IsAlive属性允许一个人识别那些真正已经死亡的,而无需创建对那些可能有资格进行垃圾收集的对象的强引用。对于列表中的任何弱引用何时有资格进行清理,没有特别的保证,但是1在内存压力存在的情况下,这样的资格会更及时;2在没有内存压力的情况下,时效性通常不会成为问题。

如果WeakReference的IsLive属性返回false,这意味着引用现在是并且将永远是kaput,并且无需检查其值。如果它返回true,这意味着引用可能是活动的,但只有在尝试将其值捕获到强引用中时才能真正知道。一个人不应该依赖于一个弱引用在任何特定的及时性程度上无效,也不应该接受它的价值,除非他真的对它感兴趣。如果一个人正在做一些事情,比如清理weakreference列表,删除那些已经死亡的,IsAlive属性允许一个人识别那些真正已经死亡的,而无需创建对那些可能有资格进行垃圾收集的对象的强引用。对于列表中的任何弱引用何时有资格进行清理,没有特别的保证,但有1个这样的例子
在存在记忆压力的情况下,资格将更及时;2在没有内存压力的情况下,时效性通常不会成为问题。

您是否尝试过呼叫WaitForPendingFinalizers?@Henrik,没有,因为我们没有想要等待的终结器您是否尝试过呼叫WaitForPendingFinalizers?@Henrik,没有,由于我们没有想要等待的终结器,我一直认为Collect方法在默认情况下会被阻止,你有没有消息说它不会被阻止?@Ian:我想你可能是对的。无论哪种方式,我都找不到任何确定的文档来证实。除非您运行的是工作站GC的非并发版本,否则GC本身不一定在整个集合期间挂起所有应用程序线程,但我在这里做了一些测试,表明Collect方法正在阻塞。也许专家可以给出一些具体的答案……我一直认为Collect方法在默认情况下会被阻止,你有没有消息说它不会被阻止?@Ian:我想你可能是对的。无论哪种方式,我都找不到任何确定的文档来证实。除非您运行的是工作站GC的非并发版本,否则GC本身不一定在整个集合期间挂起所有应用程序线程,但我在这里做了一些测试,表明Collect方法正在阻塞。也许专家能给出一些具体的答案。。。