Recently I noticed a small bug in my code which uses Reactive Extensions. I was subscribing to Timer but I never disposed my subscription. This resulted in a memory leak.
I created snippet whic开发者_如何学Ch highlights this danger:
while (true)
{
Observable.Timer(TimeSpan.Zero, TimeSpan.FromMinutes(1)).Subscribe(Console.WriteLine);
}
Is this normal behaviour?
Shouldn't scheduler hold weak reference to timer to get it garbage collected when subscribers lost connection with the rest of the app?
You can keep a reference to the subscription, and even combine them with a CompositeDisposable
, but the usual method of managing IObservable
lifetime on an otherwise infinite operator (like Timer
) is by using an operator that applies termination rules to another, like Take
(take x values), TakeWhile
(take values while f(x)
returns true) or TakeUntil
(take values until another sequence, y, emits a value or completes).
Running Rx operators won't be automatically GC'd unless they've completed. Timer
/ Interval
, for example, both recursively schedule their next value using an IScheduler
and the default instances of the various schedulers are all accessible via static properties of Scheduler
. This makes the running operator always rooted and therefore unavailable for GC.
This is normal, and is a feature.
The semantics for Subscribe() are listen forever, or until Disposed() or OnCompleted(), or OnError(), which ever comes first.
I don't agree with the answer. What you're essentially doing is redundant as you're using an infinite loop to create successive observables, hence the memory leak. Remove the while loop and just have one Observable.Timer or even better use an Observable.Interval. Just one instance then when you don't need it anymore call dispose on it.
精彩评论