Memoryleak in the heatmap?

Apr 5, 2013 at 7:50 AM
Hello,

I've used oxyplot (which is great); but I have a memory leak while using the heatmap in wpf.
Every couple of seconds, I update the data of the heatmap like so:
heatMapSeries.Data = dataValues;
  • refresh plotmodel
However, I see in the Wpf.ShapesRenderContext that the dictionary imageCache keeps growing. After a couple of minutes, I have several OxyImages stored in that cache, and it doesn't seem to release it?

Kind regards
Apr 5, 2013 at 8:09 AM
Edited Apr 5, 2013 at 8:27 AM
Could it be that the CleanUp method in the rendercontext is not called?
I tried overriding the Render method, call the base and then call the cleanup method myself, but it throws an collection modified exception. Sadly :)

I've looked in the sourcecode

// Find the images in the cache that has not been used since last call to this method
            var imagesToRelease = this.imageCache.Keys.Where(i => !this.imagesInUse.Contains(i));

            // Remove the images from the cache
            foreach (var i in imagesToRelease)
            {
                this.imageCache.Remove(i);
            }

            this.imagesInUse.Clear();
There may be a bug in here. I would call the ToList() at the end of the first line.

Kind regards
Coordinator
Apr 18, 2013 at 7:54 AM
Thanks for reporting the bug! This should be investigated closer. It should also be checked that the cache is being cleared properly when the control is unloaded.
I added the issue: https://oxyplot.codeplex.com/workitem/10042
Apr 23, 2013 at 7:30 PM
Edited Apr 23, 2013 at 7:48 PM
Can you please provide a heat map project example using WPF. I really appreciate your time and effort.

I am using WPF, Visual Studio 2012, C#, .Net4.0
Kind Regards
Coordinator
Apr 24, 2013 at 9:12 AM
Edited Apr 24, 2013 at 9:17 AM
I prefer to add examples to the cross-platform ExampleLibrary, but will try to make a WPF example for the HeatMapSeries in the Examples/Wpf/WpfExample application later. Can you propose an interesting example? It is more fun showing some real data than dummy values :)
Apr 26, 2013 at 3:21 AM
I can give real data like crude oil. Do you need it? please let me know. I will send it to you.
Apr 26, 2013 at 7:29 AM
Apr 27, 2013 at 3:49 AM
Thanks guys for the fast replies. for some reason I could not run access to the web location you just sent . But fortunately I done what I need and here is portion of my code.

I had many challenges to set the contours, contour labels and colorAxis position (Needed to add a transparent axis to push the ColorAxis further for plotArea)
By the way this is great tool. Much better than some marketed tools "like Infragistics for example).
Good job guys.

!!!!!!!!!!!!!!!!!!!!!!!!!!! ----------------------- in the XAML

<Window x:Class="TreeMapInfragistics.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:oxy="clr-namespace:OxyPlot.Wpf;assembly=OxyPlot.Wpf"
    xmlns:oxy2="clr-namespace:OxyPlot.Series;assembly=OxyPlot"
    Title="MainWindow" Height="610" Width="610">
<Grid>
    <oxy:Plot x:Name="MyOxyPlot" Model="{Binding MyPlotModelTab3}"/>
</Grid>
</Window>


!!!!!!!!!!!!!!!!!!!!!!!!!!! ----------------------- in the ViewModel

using System;
using System.Linq;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;

namespace HeatMapWithContours
{
public class MainViewModel: BaseViewModel
{
    public double [] mnMxXY = new double[6];
    public double[] WOB;
    public double[] RPM;

    public MainViewModel()
    {
        UpdateChart();
    }

   // ..........................................
   private PlotModel _myPlotModelTab3;
   public PlotModel MyPlotModelTab3
   {
       get { return _myPlotModelTab3; }
       set
       {
           _myPlotModelTab3 = value;
           OnPropertyChanged("MyPlotModelTab3");
       }
   }

   public void UpdateChart()
   {
       double[,] MyData = GenerateData();

       #region  HeatMapSeries

       var hm = new HeatMapSeries();
       hm.Data = MyData;
       hm.Selectable = false;
       hm.X0 = mnMxXY[0]; // Min X-axis
       hm.X1 = mnMxXY[1]; // Max X-axis

       hm.Y0 = mnMxXY[2]; // Min Y-axis
       hm.Y1 = mnMxXY[3]; // Max Y-axis

       #endregion

       #region ContourSeries

       var cs = new ContourSeries()
       {
           // ..............
           ColumnCoordinates = WOB, //yvalues
           RowCoordinates = RPM,//xvalues
           Data = MyData,

           // ............
           ContourLevelStep = 5,
           StrokeThickness = 0.5,
           LineStyle = LineStyle.Solid,
           Color = OxyColors.Gray,
           //ContourColors = new[] { OxyColors.SeaGreen, OxyColors.RoyalBlue, OxyColors.IndianRed },

           // ...............
           LabelFormatString = "[0.00]",
           LabelBackground = null,
           //LabelSpacing  = double.NaN,
           //Font = null,
           //LabelStep = 10,
           FontSize = 11,
           FontWeight = FontWeights.Normal,
           TextColor = OxyColors.Black
           //Background = OxyColor.FromAColor(220, OxyColors.White),
           //TrackerFormatString = null,

       };

       #endregion

       #region X- Axis

       LinearAxis xAxis = new LinearAxis
       {
           Position = AxisPosition.Bottom,
           Title = "RPM",
           ClipTitle = true,
           TitlePosition = 0.5,
           MinorGridlineStyle = LineStyle.Dot,
           MajorGridlineStyle = LineStyle.Dot,
           MinorGridlineThickness = 1,
           MajorGridlineThickness = 1,
           IsAxisVisible = true,
           IsZoomEnabled = false,
           IsPanEnabled = false,
           Angle = 0,
           AxisTitleDistance = 4,
           AxisTickToLabelDistance = 4,
           MajorTickSize = 7,
           MinorTickSize = 4,
           Minimum = mnMxXY[0],
           Maximum = mnMxXY[1],
           ShowMinorTicks = true
       };

       #endregion

       #region Y- Axis

       LinearAxis yAxis = new LinearAxis
       {
           Position = AxisPosition.Left,
           Title = "WOB",
           ClipTitle = true,
           TitlePosition = 0.5,
           MinorGridlineStyle = LineStyle.Dot,
           MajorGridlineStyle = LineStyle.Dot,
           MinorGridlineThickness = 1,
           MajorGridlineThickness = 1,
           IsAxisVisible = true,
           IsZoomEnabled = false,
           IsPanEnabled = false,
           Angle = 0,
           AxisTitleDistance = 4,
           AxisTickToLabelDistance = 4,
           MajorTickSize = 7,
           MinorTickSize = 4,
           Minimum = mnMxXY[2],
           Maximum = mnMxXY[3],
           ShowMinorTicks = true
       };

       #endregion

       #region Y1- Axis

       LinearAxis y2Axis = new LinearAxis
       {
           Position = AxisPosition.Right,
           IsAxisVisible = true,
           IsZoomEnabled = false,
           IsPanEnabled = false,

           TicklineColor = OxyColors.Transparent,
           AxislineColor = OxyColors.Transparent,
           TextColor = OxyColors.Transparent
       };

       #endregion

       #region ColorAxis

       ColorAxis cAxis = new ColorAxis
       {
           Position = AxisPosition.Right,
           PositionTier = 1,
           Palette = OxyPalettes.Jet(500),
           HighColor = OxyColors.Red,
           LowColor = OxyColors.Blue,
           Minimum = mnMxXY[4],
           Maximum = mnMxXY[5],
           StartPosition = 0.05,
           EndPosition = 0.95,
           IsAxisVisible = true,
           Angle = 0,
           AxisTitleDistance = 4,
           AxisTickToLabelDistance = 4,
           MajorTickSize = 7,
           MinorTickSize = 4,
           ShowMinorTicks = true,
           UseSuperExponentialFormat = true
       };

       #endregion

       #region PlotModel

       PlotModel tempPlotModel = new PlotModel();

       tempPlotModel.AutoAdjustPlotMargins = true;
       tempPlotModel.PlotAreaBackground = OxyColors.Red;
       tempPlotModel.Title = "Critical Speed Map (XPos)";
       tempPlotModel.TitleFontWeight = FontWeights.Normal;
       tempPlotModel.PlotAreaBorderThickness = 1;
       tempPlotModel.PlotAreaBorderColor = OxyColors.Black;

       tempPlotModel.Axes.Add(xAxis);
       tempPlotModel.Axes.Add(yAxis);
       tempPlotModel.Axes.Add(y2Axis);

       tempPlotModel.Axes.Add(cAxis);
       tempPlotModel.Series.Add(hm);
       tempPlotModel.Series.Add(cs);

       #endregion

       MyPlotModelTab3 = tempPlotModel;
  }

   #region Generate Data

   private double[,] GenerateData()
   {
            ..........
       }
}
}
Coordinator
Apr 29, 2013 at 11:23 AM
manhoihur: crude oil data sounds good if it is ok to publish under MIT license.
This bug is high priority (I don't want memory leaks in this library), but it is possible I need some time to solve this...
May 22, 2013 at 9:18 AM
I also experienced those memory leaks. My impression was that it comes from the image rendering which is kinda memory intensive, when you have unfavorable data or huge amounts of data.
I.e.: A huge spectrum of values needs way more rendering, than a small spectrum of values.

Could you provide what kind of data is used?
Aug 28, 2013 at 1:22 PM
This is also happening in an ImageAnnotation (https://oxyplot.codeplex.com/discussions/454756).

Any news on a fix for this? Or a pointer on where to look in the code and i'll give it a go myself.
Coordinator
Aug 28, 2013 at 1:40 PM
For WPF: set a breakpoint in the CleanUp() method in ShapesRenderContext. It seems I have forgot to call it...
Coordinator
Aug 28, 2013 at 1:48 PM
I have submitted a fix, let us know if this solves the problem!
Sep 4, 2013 at 10:33 AM
objo wrote:
I have submitted a fix, let us know if this solves the problem!
Yes, you fixed it! Thank U very much!
I tested the new version with a huge ImageAnnotation, and the program's memory leak disappeared.