real-time charting memory leak

Jul 28, 2009 at 4:27 PM

I'm using the toolkits charting to provide some real-time data to the user. Everything works fine, except that I am showing significant performance issues when I've been charting for over an hour or so. My charts data is bound to an ObservableCollection of Pair objects. I am only keeping the most recent 30 min worth of data (calling ObservableCollection.Remove(Pair) to remove the data), so ideally I should not see any performance loss past 30 minutes of charting I would think.

I am sure that my data is being removed correctly. When the chart is not open in the application, I am still logging my data and I experience no performance issues, even after several hours of running. The moment I start charting the data, CPU and memory jump up a bit, which is to be expected, but they then increase indefinitely. Is the chart doing some under-the-hood caching of my data so that it's not being properly garbage collected? Is it redrawing/calculating these points even though they don't actually show up in the graph? Any ideas of a work-around would be greatly appreciated.



Jul 31, 2009 at 1:52 PM

Anyone know anything about this? Looks like I'm going to have to go to a third-party vendor if I can't find a fix for this.

Aug 6, 2009 at 12:21 AM


If you could please share a simple, self-contained demonstration of this problem, I'd very much appreciate it. A small handful of people have reported issues like this over the months, but so far the issues have turned out to be bogus or no self-contained demo could be created. If you're able to do so, we'll have a look and try to sort out what's going on here.


Aug 6, 2009 at 1:41 PM

Sure thing. I wrote a simple sample app that illustrates the problem I'm running into. Let me know if you need anything else.

I have created a DataProvider class that simply creates a new random data point every second and adds it to an ObservableCollection of CPair objects (essentially a tuple). I then remove the first item in that collection so that the collection size should remain unaltered.

        <WPFToolkit:Chart Title="WPFToolkit Test" DataContext="{Binding}" Name="MainChart">
                <WPFToolkit:LinearAxis Orientation="Y" Minimum="0" ShowGridLines="True" />
                <WPFToolkit:DateTimeAxis Orientation="X" />
                <WPFToolkit:AreaSeries Title="Random Data" ItemsSource="{Binding Path=DataCollection}"  IsSelectionEnabled="True"
                                       DependentValueBinding="{Binding Path=Second}" IndependentValueBinding="{Binding Path=First}">
                        <Style TargetType="WPFToolkit:AreaDataPoint">
                            <Setter Property="Background" Value="Red"/>
                            <Setter Property="Visibility" Value="Collapsed"/>

public class DataProvider : INotifyPropertyChanged
		public ObservableCollection<CPair<DateTime, Double>> DataCollection { get; set; }
		public event PropertyChangedEventHandler PropertyChanged = delegate { };

		private bool bPause;
		private Timer SecondTimer;
		private Random RandomDataGenerator;
		private MainWindow MainWindow_;
		public delegate void DTimerEvent(CPair<DateTime, Double> pair);
		public event DTimerEvent TimerEvent;
		public event DTimerEvent DTE;

		public DataProvider(MainWindow MainWindow_)
			this.MainWindow_ = MainWindow_;

			SecondTimer = new Timer() { Interval = 1000, Enabled = true, AutoReset = true };
			SecondTimer.Elapsed += new ElapsedEventHandler(SecondTimer_Elapsed);
			TimerEvent += new DTimerEvent(DataProvider_TimerEvent);
			DTE += DataProvider_TimerEvent;

			RandomDataGenerator = new Random();
			DataCollection = new ObservableCollection<CPair<DateTime, Double>>();

			for (int i = 200; i > 0; i--)
				DateTime DT = new DateTime((DateTime.Now.Subtract(new TimeSpan(0, 0, i))).Ticks);
				DataCollection.Add(new CPair<DateTime, double>(DT, RandomDataGenerator.NextDouble() * 100));


		public void DataProvider_TimerEvent(CPair<DateTime, double> pair)

		private void SecondTimer_Elapsed(object sender, ElapsedEventArgs e)
			CPair<DateTime, Double> pair = new CPair<DateTime, Double>(DateTime.Now, RandomDataGenerator.NextDouble() * 100);
			MainWindow_.Dispatcher.Invoke(DTE, pair);

After running this code for over an hour, I have seen an obvious and fairly substantial trend of the memory footprint increasing. Again, let me know if you need anything else and thanks for looking at this!


Aug 7, 2009 at 5:58 PM


Thanks very much for the sample! I see the behavior you're reporting and there's nothing about your code that stands out to me as being wrong. Today's my last day before a week of vacation, so I can't promise I'll have time to get to the bottom of this today, but I'll follow up when I'm back and let you know what I find.


Aug 10, 2009 at 6:03 PM

Thanks for looking into this - I look forward to hearing back from you!

Aug 18, 2009 at 12:06 AM

I spent a bit of time looking at this in WinDbg/SOS just now and didn't see any smoking guns. The big memory consumption was largely due to animation-related stuff and there were more AreaDataPoints than necessary (though I hadn't forced a GC). So maybe there's a DataPoint leak and maybe there's a leak of animation-related stuff. I've opened a bug in our internal database to follow up on this further as time permits.

Thanks again for the help!!

Sep 2, 2009 at 6:51 PM

I'm running into the same (or at least similar) problem dislpaying data that changes frequently.  Any updates? Any workarounds?

Sep 21, 2009 at 3:48 PM

davidans -

Since the memory consumption issue seems to be caused by the "animation-related stuff", is there a way to disable the animation?  I'd like to give that a try and see if it fixes my problem.

Also, I am now using the "Development Release 1" build and still seeing the memory consumption issue.


John Myczek

Feb 22, 2010 at 5:10 PM

I am having difficulty using the WPF Chart Toolkit for real time data visualization.

As an example, I have an area chart that has seven series in it. Each series uses an in-memory collection for its source of data; each collection has about 22 elements that are X/Y coordinates. This is small set of data by almost any standard.

When I update the data on just one series at the rate of once-per-second by setting the series’ ItemSource property, my CPU usage for the application rises from 1% to an average of 12-15%, and occasionally spikes to the 20s. If I set all seven series in a single method that is called at once-per-second, I see an average CPU usage of 60-65% with spikes as in the 90s. Reducing the interval to as little as once every five seconds didn't seem make much impact on performance either.

I have verified through code isolation that setting the ItemSource property is what is bogging down the CPU. I have also used the WPF Performance Suite (Wndows SDK)  to verify that it is in fact the chart control that is responsible for the usage during that time.

I’m not using an observable collection, because it is possible that most of my data in each series won’t closely resemble the data set from the previous update.

As my application runs, I have also witnessed continuous increase in memory (reaching over 100 megs) for this limited sample. I have not yet had a chance to performance tune the memory aspect of things, so this might reflect some needed optimizations.

Based on this, I don’t see how it could be used in a lot of “real time visualization” scenarios such as instrumentation applications—especially where larger sets of data might be required, multiple charts per screen, and/or other applications need to be running in the background.

Feb 22, 2010 at 9:16 PM

You are most likely not seeing  a memory leak.  If you'd force a GC collection you'd most likely see the memory consumtion for the process drop to where it started. Your short lived obejct most likeley get promoted into a higher GC generation. If this is really the case there isn't any action you have to take, because the  GC  WILL reclaim the memory when it is needed.

Apr 2, 2010 at 10:17 PM

Well i am seeing the same problem of memory growing over time, and it doesnt seem to be the issue of objects waiting for GC collect. If i let it run over time, it would eventually crash due to memory usage. Has there been any update on this issue?

Apr 2, 2010 at 11:22 PM
Can somebody post the source code that they are testing? I am having a hard time getting the data binding setup in the sample that syazi posted. Thanks
Apr 3, 2010 at 12:21 AM
Edited Apr 3, 2010 at 2:55 PM

The code is below(its not complete but you will get an idea). It has a List of 60 samples, and as new samples comes, i remove the first item and add the new item at the point, thus giving a "moving" data for charting.  I was profiling with ANTS Memory profiler and it seems the leak is in LineDataPoints. Within  1 min, the memory used by instances of LineDataPoint increased by 397%. I am guessing for every data point a new instance is being created and old instances, which moved out of charting axis range, are not being released.


<chartingToolkit:Chart Grid.Row="1" HorizontalAlignment="Stretch" Title="{Binding Path=CounterHelp, Source={StaticResource CounterViewModel}}" x:Name="chart_PerfCounters" Style="{DynamicResource ChartStyle1}">
	<chartingToolkit:LineSeries x:Name="CounterLine" Title="Counter" ItemsSource="{Binding Path=SampleCollection, Source={StaticResource CounterViewModel}}" IndependentValueBinding="{Binding Index}" DependentValueBinding="{Binding Sample}" Style="{DynamicResource LineSeriesStyle}">
			<chartingToolkit:LinearAxis Orientation="Y" Title="{Binding Path=CounterName, Source={StaticResource CounterViewModel}}" Minimum="0" ShowGridLines="True"/>
		<chartingToolkit:LinearAxis Orientation="X" Title="Time" Interval="10" ShowGridLines="True"/>


 class DataForChart{ 
 	LinkedList<PerfCounterViewModel.SamplePoint> Samples;
	int MAX_SAMPLES = 60;	int CurrentIndex =0;
//This functions gets called periodically on a timer
public void UpdateGraph(float currentSample)        
 	if (Samples.Count == MAX_SAMPLES)            
	Samples.AddLast(new PerfCounterViewModel.SamplePoint(CurrentIndex++, RoundSample(currentSample))); 
	PerfViewModel.SampleCollection = new List(Samples);        

class PerfCounterViewModel : INotifyPropertyChanged
        public class SamplePoint
            public SamplePoint(int index, float sample)
                Index = index;
                Sample = sample;

            public int Index { get; set; }
            public float Sample { get; set; }

        List<SamplePoint> sampleCollection;
        public List<SamplePoint> SampleCollection
            get { return sampleCollection; }
                sampleCollection = value;
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("SampleCollection"));



Apr 3, 2010 at 7:11 PM

On further investigations, it seems when DataPoints move out of charting axis, they go into a hidden state, but they are in memory, not disposed. Which would explain the increasing memory over time with real time data. This is such a bummer, i was hoping it is just a bug.

Now i probably need to go hunting for a 3rd party control :(, unless they add the feature to only keep specified number or visible DataPoints in memory.