Memoryleak in the heatmap?

Oystein Bjorke 10 years ago 0
This discussion was imported from CodePlex

EydenJones wrote at 2013-04-05 09:50:

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

EydenJones wrote at 2013-04-05 10:09:

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

objo wrote at 2013-04-18 09:54:

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

NejibCh wrote at 2013-04-23 21:30:

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

objo wrote at 2013-04-24 11:12:

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 :)

ManhoiHur wrote at 2013-04-26 05:21:

I can give real data like crude oil. Do you need it? please let me know. I will send it to you.


NejibCh wrote at 2013-04-27 05:49:

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()
   {
            ..........
       }
}
}

objo wrote at 2013-04-29 13:23:

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...

guevara123 wrote at 2013-05-22 11:18:

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?

willmoore88 wrote at 2013-08-28 15:22:

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.

objo wrote at 2013-08-28 15:40:

For WPF: set a breakpoint in the CleanUp() method in ShapesRenderContext. It seems I have forgot to call it...

objo wrote at 2013-08-28 15:48:

I have submitted a fix, let us know if this solves the problem!

yetangye wrote at 2013-09-04 12:33:

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.