В одном из моих приложений у меня проблема с производительностью, которую я не могу решить:
Приложение построено с элементами управления вводом, производными от класса TextBox, имеющими собственный ControlTemplate в Themes\Generic.xaml.
Моя проблема в том, что эти элементы управления не будут выпущены после того, как они больше не будут использоваться. Если я посмотрю на них с помощью SciTech MemoryProfiler, то увижу, что они удерживаются экземпляром System.Windows.Documents.TextEditor, а экземпляр TextEditor удерживается через очередь финализатора.
Профилировщик памяти прикрепляет предупреждение к экземпляру TextEditor, говоря: "Экземпляр косвенно укоренен очередью финализатора".
Кто-нибудь знает, что здесь происходит? Разве это не разрешено напрямую из TextBox? Или я забыл что-то важное реализовать?
Дополнительная информация по реализации
Реализация некоторых из этих производных элементов управления очень проста. В конструкторе класса метаданные DefaultStyleKeyProperty переопределяются, и никакие обработчики событий не присоединяются к элементам, содержащимся в шаблоне элемента управления. Что-то типа:
public class MyDerivedTextBox : TextBox{
static MyDerivedTextBox(){
DefaultStyleKeyProperty.OverrideMetadata(typeof(MyDerivedTextBox), new FrameworkPropertyMetadata(typeof(MyDerivedTextBox)));
}
}
(Упрощенный) стиль выглядит примерно так:
<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>
Ответ 1 · рейтинг 3 · HCL
Очередь финализатора
Ответ на вопрос об очереди финализатора заключается в том, что наблюдаемый эффект не является постоянным: финализация просто не была завершена в тот момент, когда я анализировал память. Проблема здесь в том, чтобы понять инструмент (и среду), который я использовал.
Утечка памяти
Однако сама утечка была настоящей проблемой, и оказалось, что это то же самое я также наблюдал в других местах (в том же приложении). Привязки к CLR-свойствам классов, не реализующих INotifyPropertyChanged! http://support.microsoft.com/kb/938416/en-us
Это был один из моих первых проектов WPF, и со временем он превратился в огромное приложение. В то время, когда я начинал, я не знал, что WPF имеет проблемы с привязками, упомянутыми выше, и во время разработки я пытался сделать как можно больше с привязкой данных, но не заботился о целевых объектах. Теперь, когда приложение стало таким большим и количество клиентов резко увеличилось, эти проблемы с памятью выявились (и привели к очень странным эффектам).
После решения наиболее проблемных привязок также резко уменьшился эффект очереди финализатора. Похоже, что раньше утечки памяти приводили к отложенному выполнению финализации объекта (это только предположение, глубже в GC-поведении не копался).
Производные текстовые поля
Я создал небольшой пример проекта с такими производными элементами управления текстовыми полями, используя их в некоторых стресс-тестах в профилировщике памяти. Насколько я могу судить по своим наблюдениям за тестовым проектом, вывод из текстовых полей, как я это делал, работает отлично.
Fazit
Я могу только подчеркнуть важность проверки целевых объектов Bindings во время создания приложения. В противном случае потребуется много работы по выявлению узких мест в приложении. Я надеюсь, что это объяснение поможет кому-то не совершать тех же ошибок, что и я.
Ответ 2 · рейтинг 1 · SergioL
Не уверен, что это что-то изменит, но вместо статического конструктора под вашим контролем вы пробовали что-то вроде:
public MyDerivedTextBox()
{
this.DefaultStyleKey = typeof(MyDerivedTextBox);
}
Это схема, с которой я больше знаком. Возможно, MetaDataOverride делает что-то шаткое.
Кроме того, одна вещь, которую я заметил при некоторых проблемах с памятью Silverlight, это наличие необъяснимых AutomationPeers, вызванных службами ввода Tablet PC (см. http://www.wintellect.com/CS/blogs/sloscialo/archive/2011/04/13/silverlight-memory-leaks-and-automationpeers.aspx).