5

最近我注意到我的代码中有一个使用 Reactive Extensions 的小错误。我订阅了 Timer,但我从未处理过我的订阅。这导致了内存泄漏。

我创建了突出显示这种危险的片段:

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

这是正常行为吗?

当订阅者与应用程序的其余部分失去连接时,调度程序不应该持有对计时器的弱引用以使其垃圾收集吗?

4

3 回答 3

7

可以保留对订阅的引用,甚至将它们与 a 结合使用,但在其他无限运算符(如)上CompositeDisposable管理生命周期的常用方法是使用将终止规则应用于另一个运算符的运算符,如(取 x 值),(在返回 true 时取值)或(取值直到另一个序列y发出一个值或完成)。IObservableTimerTakeTakeWhilef(x)TakeUntil

除非完成,否则运行的 Rx 运算符不会被自动 GC'd。Timer/Interval例如,两者都使用 an 递归调度它们的下一个值,IScheduler并且各种调度程序的默认实例都可以通过 的静态属性访问Scheduler。这使得运行中的操作符始终是 root 的,因此对 GC 不可用。

于 2011-06-06T06:48:05.723 回答
4

这是正常的,并且是一个特性

Subscribe() 的语义是永远监听,或者直到 Disposed() 或 OnCompleted() 或 OnError(),以先到者为准。

于 2011-06-06T03:27:25.427 回答
1

我不同意这个答案。您本质上所做的事情是多余的,因为您使用无限循环来创建连续的可观察对象,因此存在内存泄漏。删除 while 循环,只使用一个 Observable.Timer,甚至更好地使用 Observable.Interval。只有一个实例,然后当您不再需要它时,调用 dispose 就可以了。

于 2014-06-04T10:28:58.430 回答