Observable.Timer()会导致内存泄漏吗?

5

最近我注意到我的代码中有一个小错误,它使用了Reactive Extensions。我订阅了计时器,但从未释放我的订阅。这导致了内存泄漏。

我创建了一个片段来突出显示这个危险:

while (true)
{
    Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)).Subscribe(Console.WriteLine);
}

这是正常行为吗?

调度器应该持有定时器的弱引用,以便在订阅者与应用程序的其余部分失去连接时进行垃圾回收,是吗?

3个回答

7
您可以保留对订阅的引用,甚至与CompositeDisposable结合使用,但是通常管理IObservable在无限运算符(如Timer)上的生命周期的方法是使用一个将终止规则应用于另一个运算符的运算符,例如Take(获取x个值),TakeWhile(当f(x)返回true时获取值)或TakeUntil(获取值,直到另一个序列y发出值或完成)。
Rx运算符不会自动GC,除非它们已经完成。例如,Timer / Interval都使用IScheduler和各种调度程序的默认实例递归地安排其下一个值,并且所有这些调度程序的静态属性都可以通过Scheduler访问。这使得正在运行的运算符始终被根据,因此无法进行GC。

4

这是正常的,也是一种特性。

Subscribe() 的语义是永久监听,直到 Disposed()、OnCompleted() 或 OnError() 中的任何一个被触发。


1
我不同意这个答案。你所做的实际上是多余的,因为你正在使用一个无限循环来创建连续的 observables,从而导致内存泄漏。删除 while 循环,只使用一个 Observable.Timer 或者更好地使用一个 Observable.Interval。只有一个实例,当你不再需要它时,调用 dispose 方法即可。

1
这段代码是一个简化的示例代码,以使问题更加明显。我认为作者已经意识到了你所写的内容。 - Stéphane Gourichon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接