OutOfMemoryException CustomLabels
OutOfMemoryException CustomLabels
Our application continuosly updates the graph and axis. We are encountering a memory leak that appears to be in AxisLabels. It seems the Axis is keeping an array of label positions that are computed in the draw routine, but we cannot find any code that ever removes any entries from the Array. Here is a call stack from an out of memory exception we've encountered:
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Collections.ArrayList.set_Capacity(Int32 value)
at System.Collections.ArrayList.EnsureCapacity(Int32 min)
at System.Collections.ArrayList.Add(Object value)
at Steema.TeeChart.Axis.DrawAxisLabel(ChartFont f, Int32 x, Int32 y, Int32 angle, String st, TextShape format, Boolean isTitle)
at Steema.TeeChart.Axis.DrawAxisLabel(Int32 x, Int32 y, Int32 angle, String st, TextShape labelItem)
at Steema.TeeChart.Axis.AxisDraw.DrawThisLabel(Int32 labelPos, String tmpSt, TextShape labelItem)
at Steema.TeeChart.Axis.AxisDraw.DrawCustomLabels()
at Steema.TeeChart.Axis.AxisDraw.Draw(Boolean calcPosAxis)
at Steema.TeeChart.Axis.Draw(Boolean calcPosAxis)
at Steema.TeeChart.Axes.Draw(Graphics3D g)
at Steema.TeeChart.Chart.InternalDraw(Graphics g)
at Steema.TeeChart.TChart.Draw(Graphics g)
at Steema.TeeChart.TChart.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at AudioPrecision.Common.Controls.HorizontalBar.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Collections.ArrayList.set_Capacity(Int32 value)
at System.Collections.ArrayList.EnsureCapacity(Int32 min)
at System.Collections.ArrayList.Add(Object value)
at Steema.TeeChart.Axis.DrawAxisLabel(ChartFont f, Int32 x, Int32 y, Int32 angle, String st, TextShape format, Boolean isTitle)
at Steema.TeeChart.Axis.DrawAxisLabel(Int32 x, Int32 y, Int32 angle, String st, TextShape labelItem)
at Steema.TeeChart.Axis.AxisDraw.DrawThisLabel(Int32 labelPos, String tmpSt, TextShape labelItem)
at Steema.TeeChart.Axis.AxisDraw.DrawCustomLabels()
at Steema.TeeChart.Axis.AxisDraw.Draw(Boolean calcPosAxis)
at Steema.TeeChart.Axis.Draw(Boolean calcPosAxis)
at Steema.TeeChart.Axes.Draw(Graphics3D g)
at Steema.TeeChart.Chart.InternalDraw(Graphics g)
at Steema.TeeChart.TChart.Draw(Graphics g)
at Steema.TeeChart.TChart.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at AudioPrecision.Common.Controls.HorizontalBar.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
Could you please send us an example we can run "as-is" to reproduce the problem here?
You can post your files at news://www.steema.net/steema.public.attachments newsgroup.
Could you please send us an example we can run "as-is" to reproduce the problem here?
You can post your files at news://www.steema.net/steema.public.attachments newsgroup.
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
It really doesn't take much to reproduce.
Put this into a project and look at it with a memory profiler.
We have the source and I it occurs in Axis.cs DrawAxisLabel.
The shapebounds of the label are being added to an arraylist which is never cleared. The memory profiler shows the number of allocated rectangles keeps rising which would eventually lead to an OutOfMemoryException. We are a week away from code freeze and are trying to figure out a solution.
Put this into a project and look at it with a memory profiler.
Code: Select all
private void Form1_Load(object sender, EventArgs e)
{
FastLine lines = new FastLine(tChart1.Chart);
lines.FillSampleValues(100);
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
tChart1.Axes.Bottom.Labels.Items.Clear();
tChart1.Axes.Bottom.Labels.Items.Add(1.0);
}
The shapebounds of the label are being added to an arraylist which is never cleared. The memory profiler shows the number of allocated rectangles keeps rising which would eventually lead to an OutOfMemoryException. We are a week away from code freeze and are trying to figure out a solution.
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
Thanks for the information. We could reproduce the issue here. The problem is the Steema.TeeChart.AxisLabels.labelPos field, which is an arraylist and which isn't being cleared. You can modify the Steema.TeeChart.AxisLabelsItems.Clear method. It should look like:
This fix has already been applied to current TeeChart sources and will be included with next debug build and maintenance releases.
Thanks for the information. We could reproduce the issue here. The problem is the Steema.TeeChart.AxisLabels.labelPos field, which is an arraylist and which isn't being cleared. You can modify the Steema.TeeChart.AxisLabelsItems.Clear method. It should look like:
Code: Select all
/// <summary>
/// Clear Custom Labels list
/// </summary>
#if VS2005
public new void Clear()
#else
public override void Clear()
#endif
{
#if VS2005
foreach (AxisLabelItem c in this) c.Dispose();
#else
for (int t=0; t<base.Count; t++) ((AxisLabelItem)base[t]).Dispose();
#endif
iAxis.Labels.labelPos.Clear(); //CDI new line
base.Clear();
iAxis.Chart.Invalidate();
}
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
I tried building with your changes but now I am getting an overflow in GDI when I try to draw a horizontal bar with an origin set to int.MinValue.
Building without the changes leads to the same exception.
We examined the release binary with Ildasm and found that our version of the source has different code in CalcXPosValue than in the released binary. The version in the Assembly.cs file is 2.0.2179.21171 and the released binary version we compared with is 2.0.2179.21172.
All of our testing has been done with the binary version and we are 2 days from codefreeze. Can we get a patched version of 2.0.2179.21172 with your fix?
Building without the changes leads to the same exception.
We examined the release binary with Ildasm and found that our version of the source has different code in CalcXPosValue than in the released binary. The version in the Assembly.cs file is 2.0.2179.21171 and the released binary version we compared with is 2.0.2179.21172.
All of our testing has been done with the binary version and we are 2 days from codefreeze. Can we get a patched version of 2.0.2179.21172 with your fix?
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
We have done several tests here. We have compiled the sources of the build you mentioned and compared its assemblies with the binary installers using reflection and CalcXPosValue was the same.
Also, we tried to reproduce the issue you reported without success. The code we used is:
We strongly recommend to use the latest binary and source code releases available at our Customer Download Area and apply the change we suggested in the sources.
We have done several tests here. We have compiled the sources of the build you mentioned and compared its assemblies with the binary installers using reflection and CalcXPosValue was the same.
Also, we tried to reproduce the issue you reported without success. The code we used is:
Code: Select all
private void Form1_Load(object sender, EventArgs e)
{
horizBar1.FillSampleValues();
horizBar1.UseOrigin = true;
horizBar1.Origin = int.MinValue;
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
The Utils.Round call is added by Reflector. We are unable to reproduce the issue here. Does the error happen with the assembly I sent you on Friday?
The Utils.Round call is added by Reflector. We are unable to reproduce the issue here. Does the error happen with the assembly I sent you on Friday?
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
No the error does not occur with the one you sent on Friday. I'm having difficulty explaining how reflector could add the call to Steem.TeeChart.Utils.Round.
Taking Relector out of the equation:
When I examine the latest assemblies with Ildasm it shows a call to Utils.Round but only in the released binary from Steema. The assembly that I build with the latest source does not show the call.
Taking Relector out of the equation:
When I examine the latest assemblies with Ildasm it shows a call to Utils.Round but only in the released binary from Steema. The assembly that I build with the latest source does not show the call.
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
Lookin more carefully to Reflector's output and our internal sources, the difference between them and you source version is because our TeeChart sources are like this:
Source code release should have the CHECKOVER section but for some reason it is not included. We will check it for next releases.
Lookin more carefully to Reflector's output and our internal sources, the difference between them and you source version is because our TeeChart sources are like this:
Code: Select all
/// <summary>
/// Calculates the Horizontal coordinate in pixels of Value parameter.
/// </summary>
/// <param name="value">Parameter Value </param>
/// <returns>Horizontal coordinate in pixels </returns>
public int CalcXPosValue(double value)
{
//AQTime
if (IsDepthAxis)
{
if(chart.Aspect.View3D)
return InternalCalcDepthPosValue(value);
else
return 0;
}
else
if (logarithmic)
return InternalCalcLogPosValue(true,value);
else
if (iRangezero) return iCenterPos;
else
{
// compile with #define CHECKOVER
// if you wish to avoid axis coordinates overflow when zooming,
// specially in Windows 95, 98 or Me.
#if CHECKOVER
double tmp=(value-iMinimum)*iAxisSizeRange;
tmp = inverted ? IEndPos-tmp : IStartPos+tmp;
if (tmp>MaxPixelPos) tmp=MaxPixelPos;
else
if (tmp<-MaxPixelPos) tmp=-MaxPixelPos;
return Utils.Round(tmp);
#else // faster version (no checking)...
int tmp=(int)((value-iMinimum)*iAxisSizeRange);
return inverted ? IEndPos-tmp : IStartPos+tmp;
#endif
}
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
You're welcome. Please be aware at this forum for debug builds and maintenance releases announcements.
You're welcome. Please be aware at this forum for debug builds and maintenance releases announcements.
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |
Clearing the arraylist in the Clear method will work only if we call clear before every draw. The arraylist seems to add the label positions in the draw method even if the labels have not changed.
Since we do not always clear the labels before drawing, the arraylist still grows until we get an OutOfMemoryException.
Since we do not always clear the labels before drawing, the arraylist still grows until we get an OutOfMemoryException.
It looks like the arraylist is only needed for handling the click label event. Since we do not use this feature we have implemented this workaround.
After initializing the chart we get the labelpos arraylist using reflection and subscribe to the GetAxisDrawLabel event.
Then is getaxisdrawlabel we clear the arraylist.
After initializing the chart we get the labelpos arraylist using reflection and subscribe to the GetAxisDrawLabel event.
Code: Select all
FieldInfo labelPosInfo =
chartAxis.Labels.GetType().GetField("labelPos", BindingFlags.NonPublic | BindingFlags.Instance);
if (labelPosInfo != null)
this.labelPos = labelPosInfo.GetValue(chartAxis.Labels) as ArrayList;
if (this.labelPos != null)
{
this.axis.GetAxisDrawLabel += new GetAxisDrawLabelEventHandler(chartAxis_GetAxisDrawLabel);
}
Code: Select all
void chartAxis_GetAxisDrawLabel(object sender, GetAxisDrawLabelEventArgs e)
{
//clear the list of leaking rectangles
if (this.labelPos != null)
this.labelPos.Clear();
}
-
- Site Admin
- Posts: 14730
- Joined: Mon Jun 09, 2003 4:00 am
- Location: Banyoles, Catalonia
- Contact:
Hi johnk,
If I remember correctly you already reported this issue some days ago and we fixed it in the sources and sent you the solution. The problem was at Axis.cs in Steema.TeeChart.Axis.AxisDraw, InternalDrawLabel method. It ended up being like below, we had to add the labelPos.Clear line.
BTW: This issue is already fixed in the latest debug build available at the customer area.
If I remember correctly you already reported this issue some days ago and we fixed it in the sources and sent you the solution. The problem was at Axis.cs in Steema.TeeChart.Axis.AxisDraw, InternalDrawLabel method. It ended up being like below, we had to add the labelPos.Clear line.
Code: Select all
private void InternalDrawLabel(bool decValue)
{
int tmp=axis.CalcPosValue(tmpValue);
if ((axis.labels.bOnAxis) ||
((tmp>axis.IStartPos) &&
(tmp<axis.IEndPos)))
{
if (!axis.TickOnLabelsOnly)
AddTick(tmp);
if (axis.labels.Visible)
{
axis.labels.labelPos.Clear();
DrawThisLabel(tmp, axis.labels.LabelValue(tmpValue), null);
}
}
if (decValue) axis.IncDecDateTime(false,ref tmpValue,iIncrement,tmpWhichDatetime);
}
Best Regards,
Narcís Calvet / Development & Support Steema Software Avinguda Montilivi 33, 17003 Girona, Catalonia Tel: 34 972 218 797 http://www.steema.com |
Instructions - How to post in this forum |