最近我注意到我的代码中有一个使用Reactive Extensions的小错误。我订阅了Timer,但我从未处理过我的订阅。这导致内存泄漏。
我创建了一个片段,突出了这个危险:
while (true)
{
Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)).Subscribe(Console.WriteLine);
}
这是正常行为吗?
当订阅者与应用程序的其余部分失去连接时,调度程序是否应该保留对计时器的弱引用以使其被垃圾收集?
答案 0 :(得分:6)
你可以保留对订阅的引用,甚至将它们与CompositeDisposable
结合起来,但通常的方法是在一个无限运算符上管理IObservable
生命周期(如Timer
)是通过使用将终止规则应用于其他规则的运算符,例如Take
(取x值),TakeWhile
(在f(x)
返回true时取值)或{{ 1}}(取值直到另一个序列, y ,发出一个值或完成)。
运行Rx运算符不会自动GC,除非它们已完成。例如,TakeUntil
/ Timer
都使用Interval
递归调度其下一个值,并且各种调度程序的默认实例都可以通过IScheduler
的静态属性访问。这使得运行的操作员始终具有根,因此不适用于GC。
答案 1 :(得分:4)
这是正常的,并且是功能。
Subscribe()的语义是永远监听,或直到Disposed()或OnCompleted()或OnError(),它们首先出现。
答案 2 :(得分:1)
我不同意答案。 你正在做的事情是多余的,因为你使用无限循环来创建连续的observable,因此内存泄漏。 删除while循环,只有一个Observable.Timer,甚至更好地使用Observable.Interval。只有一个例子,当你不再需要它时,就可以对它进行处理。