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 which 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With