In one of the apps of mine I have a performance problem I can’t resolve:
The app is built with input controls derived from the TextBox
-class, having their own ControlTemplate in Themes\Generic.xaml
.
My problem is, that these controls will not be released after they are no more used. If I look at them with SciTech MemoryProfiler, I see that they are hold by an instance of System.Windows.Documents.TextEditor
and the TextEditor
-instance is hold through the finalizer queue.
Memory profiler attaches a warning to the TextEditor
-instance, saying “Instance indirectly rooted by finalizer queue”.
Has anyone an idea what’s going on here? Is it not allowed to derive directly from TextBox? Or have I forgotten something important to implement?
Additional information for the implementation:
The implementation of some of these derived controls is very simple. In class constructor, the DefaultStyleKeyProperty’s metadata is overridden and no event handlers are attached to elements contained in the control template. Something like:
public class MyDerivedTextBox : TextBox{
static MyDerivedTextBox(){
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDerivedTextBox), new FrameworkPropertyMetadata(typeof(MyDerivedTextBox)));
}
}
The (simplified) style looks something like:
<Style TargetType="{x:Type myApp_controls:MyDerivedTextBox}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="UndoLimit" Value="1"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type myApp_controls:MyDerivedTextBox }">
<Border Name="Border" ... >
<ScrollViewer Margin="1" x:Name="PART_ContentHost" />
</Border>
</Setter.Value>
</Setter>
</Style>
Not sure if it will change anything, but instead of the static constructor in your control, have you tried something like:
That's the pattern I'm more familiar with. Perhaps the MetaDataOverride is doing something wonky.
As an aside, one thing I did notice with some Silverlight memory issues, was the presence of unexplained AutomationPeers brought on by Tablet PC Input Services (see http://www.wintellect.com/CS/blogs/sloscialo/archive/2011/04/13/silverlight-memory-leaks-and-automationpeers.aspx).
Finalizer queue
The answer for the question about the finalizer queue is, that the observed effect is not a constant one: The finalization was simply not finished at the point I have analyzed the memory. The problem here is to understand the tool (and the environment) I have used.
Memory Leak
The leak itselfs however was a real problem and it turned out, that it was the same thing I also observed at other positions (in the same app). Bindings to CLR-properties of classes not implementing INotifyPropertyChanged! http://support.microsoft.com/kb/938416/en-us
It was one of my first WPF projects and in the meantime it grew to a huge application. At the time I started, I was not aware, that WPF has problems with bindings mentioned above, and during development I have tried to do as much as possible with data binding but didn't care about the target objects. Now after the app has grown so big and the number of clients has increased dramatically, those memory problems came to light (and led to very strange effects).
After resolving the most problematic bindings, also the effect with the finalizer queue has been decreased drastically. It seems that before, the memory leaks had led to a deferred execution of the object finalization (this is only an assumption, I have not digged deeper into GC-behaviour).
Derived TextBoxes:
I have created a little sample project with such derived text-box controls, using them in some stresstests within memory profiler. As far as I can say from my observation of the test project, derive from TextBoxes as I did works perfectly well.
Fazit
I can only emphasize the importance of checking the target objects of Bindings during application creation. Otherwise, it will be a lot of work to identify the leaking spots in an application. I hope this explanation helps someone not doing the same mistakes as I did.