I've noticed that I have this huge memory leak.My app relies heavily on infragistics ui components, and our code createsAnd destroys many UserControls that comprise mostly of UltraTextEditors.After some research I found that the constructor is not called on ANY control that contains an UltraTextEditor (and probably other editors as well).
This seemed so weird to me that I started a new project, that contains a main form, and a single user control, which in turn contains a single UltraTextEditor. I added a destructor to this control, and set it to print a message to the debug console.To the main control I added a single button that creates my user control and looses reference to it, and then a call to GC.Collect();.
If the control contains the UltraTextEditor, the descructor is never called, if I remove the line with "this.controls.add(ultraTextEditor1); " the destructor is called as expected.Why does this happen? Is there some setting I need to know of somewhere that prevents my control from being GCed? Does the UltraTextEditor save a reference to the parent class in some static place that never gets out of scope?
I'm not sure I completely follow this. Are you disposing the UserControl too? When you add the UltraTextEditor to the UserControl's Controls collection, the UserControl itself will hold onto the reference to the editor until the UserControl itself is disposed, which is why you're are seeing everything work when you remove 'this.controls.add...".
-Matt
i'll add my test's code example to clarify the test i'm running:
public class Test : UserControl { public Test() { Debug.WriteLine("Creating control"); this.Controls.Add(new UltraTextEditor()); //this.Controls.Add(new TextBox()); } ~Test() { Debug.WriteLine("Test destructor called on user control"); } } static class Program { private static void CreateTest() { Test test = new Test(); GC.Collect(); //request GC cycle } [STAThread] static void Main() { for (int i=0; i<10; i++) CreateTest(); Debug.WriteLine("Leaving test"); } }
this test outputs:
Creating controlCreating controlCreating controlCreating controlCreating controlCreating controlCreating controlCreating controlCreating controlCreating controlLeaving test
if we comment out the infragistics control and uncomment the TextBox we get:
Creating controlCreating controlCreating controlTest destructor called on user controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlTest destructor called on user controlCreating controlLeaving test
-Yossi
Yossi,
What I believe is happening here is that the various Infragistics controls hook certain static events, such as XPThemeChanged, which will effectively root the control. If you do not explicitly dispose this control (or the Test object that you're creating), then these static events will not get unhooked, I do not think. However, the base Component class calls SuppressFinalize in its Dispose method, which means that you will not actually get a call to the finalizer when you dispose this control. Therefore you will never hit your destructor. Unless you have a very good reason though it's generally not a recommended .NET practice to use destructors and instead rely on the Dispose implementations.
Hi Matt,
i'v emailed infragistics support about this, and they say the same thing -> Infragistics control hook to static events.
1. The correct way to handle garbage collection in this case would have been to use weak references in the event, as in:
http://diditwith.net/PermaLink,guid,aacdb8ae-7baa-4423-a953-c18c1c7940ab.aspx
this will allow the objects to get collected , and their dispose method to be called implicitly by the distructor.
2. Regarding SupressFinalize, GC.SupressFinalize does not prevent the call to Dispose, but rather the redundent call to Dispose by the GC after Dispose have been called once already (the point of this function call is to prevent aggressive GC to cause rentries to the Dispose method).
As for the Control call to SupressFinalize, this call is done by the call to base.Dispose by the extending child, so in any case it's called only after the child's Dispose has executed.
3. Regarding best practices, destructors are not common and not widely used, however calling Dispose is exactly the kind of good reason you need for a destructor. it's exactly why microsoft implemented a call to Dispose in their destructor to Control.
When working in a managed environment, you expect your objects to get automatically garbage collected once you loose all references to them, this includes IDisposable objects. what i know as the best practice is to implement a destructor for all classes implementing the IDisposable interface.
as in microsoft's page on IDisposable interface : http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
The IDisposable interface is there to allow you to release resource in case want to force the release of unmanaged resources (and allows you to release managed ones if you really want to) and dont want to wait for the GC to get to your object.
it was not intended (and generally not used) as a means of unregistering from static events.
Hi Jasun,
No, there's no way to turn off the theme change hook.
That sounds like something Developer Support needs to look into. Have you submitted this to them?
Thanks for your quick response, Mike,
In my test app, the ultrabutton control has been added to the form's controls collection and does not get garbage collected after the form is closed. Our memory profiling tool indicates that the ThemeChangedDelegate is preventing it from being collected.
This problem only seems to arise when there is an UltraTabbedMdiManager present in the project- at least from my initial testing. It seems to also to be affected by the UseOSThemes property of the controls. the a global setting i can use to disable the theme delegate?
Hi Jason,
jasunbrown said:We're having the same issue. i created a stand alone app that demonstrates the flaw perfectly. The idea of having to explicitly dispose of all of our infragistcs ui controls is insane in a managed environment. Many of our controls are placed on the forms at runtime- so doing this would require code changes to maintain handles to these controls...
You really have to dispose of every control. This is not specific to Infragistics. Every control you place on a form is disposed by the form. As long as you add the control to the form's Controls collection, the form will take care of disposing it for you. You can look at the OnDispose method of the form and see the code that does this.
We're having the same issue. i created a stand alone app that demonstrates the flaw perfectly. The idea of having to explicitly dispose of all of our infragistcs ui controls is insane in a managed environment. Many of our controls are placed on the forms at runtime- so doing this would require code changes to maintain handles to these controls...
has any progress been made on this issue? please let me know if there is a simple infragistics-suggested work around. I am using v9.2. (previously, we were using v7.3, which had the same issue)
Thanks in advance
jason
Just saw your answer. Sorry about that.
I'll try it out my self :)