OutOfMemoryException running published Rx performance test
-
Friday, November 09, 2012 4:05 PM
Hi,
I'm following along in Bart's article from March this year on Rx 2.0 enhancements.
http://blogs.msdn.com/b/rxteam/archive/2012/03/12/reactive-extensions-v2-0-beta-available-now.aspx
I tried running one of the performance tests using Rx 2.0 RTM and .NET Framework 4.0, and encountered an OutOfMemoryException. Specifically, I tried this test:
static void Survival<TFittest>() { var xs = new Fast().Delay(TimeSpan.FromSeconds(5)); var c = new Count<int>(); var sw = Stopwatch.StartNew(); using (xs.Subscribe(c)) Thread.Sleep(30000); sw.Stop(); Console.WriteLine(c.Total / sw.Elapsed.TotalSeconds + " msgs/s"); }
This is supposed to be a test of memory allocation related to the Delay operator. When I run this program, I get an OutOfMemoryException within a couple seconds.
Anyone have an idea why this might be happening? My machine is running at 5.46GB right now. I have 8GB of RAM. When I start the process, memory grows to 6.22GB and then the process dies.
Interesting if I change the delay to 1 ms, I still get an OutOfMemoryException.
Any ideas why this is happening?
Thanks,
Ranjith
All Replies
-
Friday, November 09, 2012 5:36 PM
Hi Ranjith,
I can't reproduce the problem with .NET 4.5. I didn't try with .NET 4.0 though. Maybe you could try against .NET 4.5?
I just tested against Rx 2.0.21103.1 (assembly version 2.0.20823.0) for .NET 4.5. After running the test 3 times in a row, to warm up caches, here were the final results:
110527.702672517 msgs/s
Memory <= 600 MB
~2 garbage collectionsMy computer:
Windows 8 Pro, x64
Intel(R) Xeon(TM) CPU 3.40GHz, 3391 Mhz, 1 Core(s), 2 Logical Processor(s)
Installed Physical Memory (RAM) 4.00 GB
Available Physical Memory 1.91 GBHere is the complete code, taken from the Rx Team's blog post:
Note: I've changed it slightly to run inside of a lab application, so technically the code was hosted in a WPF UserControl instead of a console window during my tests, though I suspect that if I were to run a pure console app the results would be the same.
using System; using System.Diagnostics; using System.Reactive.Disposables; using System.Reactive.Linq; using System.Threading; namespace Rxx.Labs.Performance { public sealed class DelayThroughputLab : BaseConsoleLab { protected override void Main() { var xs = new Fast().Delay(TimeSpan.FromSeconds(5)); var c = new Count<int>(); var sw = Stopwatch.StartNew(); using (xs.Subscribe(c)) Thread.Sleep(30000); sw.Stop(); TraceLine(c.Total / sw.Elapsed.TotalSeconds + " msgs/s"); } class Count<T> : IObserver<T> { public int Total; public void OnNext(T value) { Total++; } public void OnError(Exception error) { throw new NotImplementedException(); } public void OnCompleted() { throw new NotImplementedException(); } } class Fast : IObservable<int> { public IDisposable Subscribe(IObserver<int> observer) { var d = new BooleanDisposable(); new Thread(() => { while (!d.IsDisposed) observer.OnNext(42); }).Start(); return d; } } } }- Dave -
Friday, November 09, 2012 5:54 PM
Hi Ranjith,
I just tested in a console app targeting .NET 4.0 and I still couldn't reproduce your error. The results were similar to my previous test targeting .NET 4.5.
- Dave
-
Friday, November 09, 2012 7:47 PM
Hmmm. Thanks for testing, Dave. I'm not sure what I'm doing wrong. I created a console app targeting .NET Framework 4, and I'm running it on Windows 7 Enterprise. I tried compiling the app as 64 bit, but that didn't help.
Here's my exact code:
namespace Performance
{
class Program
{
static void Main(string[] args)
{
var xs = new Fast().Delay(TimeSpan.FromSeconds(5));
var c = new Count<int>();
var sw = Stopwatch.StartNew();
using (xs.Subscribe(c))
Thread.Sleep(30000);
sw.Stop();
Console.WriteLine(c.Total / sw.Elapsed.TotalSeconds + " msgs/s");
}
class Count<T> : IObserver<T>
{
public int Total;
public void OnNext(T value)
{
Total++;
}
public void OnError(Exception error)
{
throw new NotImplementedException();
}
public void OnCompleted()
{
throw new NotImplementedException();
}
}
class Fast : IObservable<int>
{
public IDisposable Subscribe(IObserver<int> observer)
{
var d = new BooleanDisposable();
new Thread(() =>
{
while (!d.IsDisposed)
observer.OnNext(42);
}).Start();
return d;
}
}
}
}
-
Saturday, November 10, 2012 11:04 AM
Hi Ranjith,
Have you tried running a profiler such as Visual Studio, PerfView or CLRProfiler? Perhaps it would be useful to see the actual allocations and the hot execution path.
- Dave
-
Saturday, November 10, 2012 11:05 AM
Hi Ranjith,
Just to be clear, have you updated to the latest version of Rx 2.0? You can download it from NuGet. This is the version that I used when testing.
- Dave

