Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactiveUI ObservableAsPropertyHelper / Reactive Extensions Memory Leak?

I noticed that in my .NET 3.5 application, which uses ReactiveUI, I have a significant memory leak that seems to originate in ObservableAsPropertyHelper. I created a test project to demonstrate it here.

It seems that every change notification triggered by a simple ObservableAsPropertyHelper calculated property leaks memory. The leak seems to originate in Reactive Extensions, not directly in ReactiveUI, but my use of OAPH is so simple that I wonder if anyone has encountered this or may have a proposed fix.

The severity of the memory leak varies between .NET 3.5 (RxUI 2.4, Rx 1.1) and .NET 4.0 (RxUI 4.2, Rx 2.0.3). It is much closer to linear with every update of the property in .NET 3.5. However, the leak is still there in .NET 4.0.

I have uploaded the test project and some profiler images for my .NET 3.5 and .NET 4.0 test session with the test application, here.

You can see in the images that the object graphs are different, so we may be talking about two different leaks entirely. In the 4.0 session (40_RetentionGraph.png) you can see that the most allocated objects are Ints (the type of my OAPH property) and ConcurrentQueue. There seems to be some kind of circular reference issue going on there. You can also see in 40_IntsAllocatedGCRootGrows.png that the distance from GC root of the instances grows.

In the 3.5 version (which I'm most concerned about), you can see (35_Summary.png) that the most allocated objects are Action and ScheduledObserver. The object graph is a bit more complex and altogether different than the 40 version.

I've reviewed this discussion but haven't found a direct answer: my scenario is, very simple updates to OAPH. Any insight on possible solutions to this leak is appreciated.

like image 426
Udi Bar-On Avatar asked May 21 '13 11:05

Udi Bar-On


1 Answers

You haven't specified a scheduler, so by default RxUI is going for the DispatcherScheduler. Since your app is a console app there is no running Dispatcher. All that memory is being consumed by the OnNext's queueing up with nothing to run them.

You could mess about with firing up a dispatcher and feeding it frames to run (which a WPF app would do for you), or for the sake of testing just change the ReactiveTester constructor from this:

public ReactiveTester()
{
  _Total = this.WhenAny(x => x.A, x => x.B, (a, b) => a.Value + b.Value)
               .ToProperty(this, x => x.Total);
}

To this:

public ReactiveTester()
{
  _Total = this.WhenAny(x => x.A, x => x.B, (a, b) => a.Value + b.Value)
               .ToProperty(this, x => x.Total, 0, Scheduler.CurrentThread);
}

And everything will be just rosy.

like image 124
James World Avatar answered Oct 20 '22 06:10

James World