Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Observable.Timer() lead to memory leaks?

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?

like image 959
StanislawSwierc Avatar asked Jun 05 '11 22:06

StanislawSwierc


2 Answers

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.

like image 148
Richard Szalay Avatar answered Sep 28 '22 03:09

Richard Szalay


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.

like image 39
Scott Weinstein Avatar answered Sep 28 '22 03:09

Scott Weinstein