Я пишу программу, которая использует кучу двусторонних привязок, и объем используемой памяти стал огромной проблемой. В моем полном приложении я начинаю с 50 МБ, а затем, просто используя привязки (т. Е. Изменяя значение на одной стороне и позволяя привязке обновлять другую сторону), я обычно ломаю 100 МБ, хотя мой код не выделил ничего нового , У меня вопрос, что это за лишняя память и что я могу сделать, чтобы ее контролировать. Я создал простой, воспроизводимый пример ниже:
Скажем, у меня есть главное окно со следующим содержимым:
<StackPanel Height="25" Orientation="Horizontal">
<TextBox UndoLimit="1" Name="TestWidth" />
<Label>,</Label>
<TextBox UndoLimit="1" Name="TestHeight" />
</StackPanel>
И затем в конструкторе этого окна я создаю новое окно, показываю его, а затем привязываю его свойства зависимостей WidthProperty и HeightProperty к переменным, которые используют INotifyPropertyChanged:
public partial class MainWindow : Window, INotifyPropertyChanged
{
private int _WidthInt;
public int WidthInt
{
get { return _WidthInt; }
set { _WidthInt = value; NotifyPropertyChanged("WidthInt"); }
}
private int _HeightInt;
public int HeightInt
{
get { return _HeightInt; }
set { _HeightInt = value; NotifyPropertyChanged("HeightInt"); }
}
public MainWindow()
{
InitializeComponent();
Window testWindow = new Window();
testWindow.Show();
Binding bind = new Binding("HeightInt");
bind.Source = this;
bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.HeightProperty, bind);
//bind.Converter = new convert();
//this.TestHeight.SetBinding(TextBox.TextProperty, bind);
bind = new Binding("WidthInt");
bind.Source = this;
bind.Mode = BindingMode.TwoWay;
testWindow.SetBinding(Window.WidthProperty, bind);
//bind.Converter = new convert();
//this.TestWidth.SetBinding(TextBox.TextProperty, bind);
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string sProp)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(sProp));
GC.Collect();
}
}
Тогда, если я постоянно изменяю размер окна, использование памяти в диспетчере задач линейно увеличивается без видимого верхнего предела. Программа начинается с 17 МБ, и в течение 30 секунд после изменения размера она увеличивается до 20 МБ и зависает после определенной точки в низких 20-х (спасибо Иану). Это на самом деле происходит, даже если нет привязок, и память не возвращается обратно. Хотя это и раздражает, это не «скачок памяти», о котором я говорю.
Если я раскомментирую строки, которые также связывают текстовые поля с переменными, я получаю следующий результат: всего за несколько секунд он скачет с 18 МБ до 38 МБ и затем зависнет там (пожалуйста, обратите внимание на настройку привязки текстового поля в XAML не влияет на всплеск памяти). Я попытался реализовать свой собственный конвертер для привязки текстового поля, но это не влияет на использование памяти.
Переход по-прежнему существует, если я изменю переменные на новые свойства зависимостей и свяжусь с ними, например,
public static readonly DependencyProperty WidthIntProperty = DependencyProperty.Register("WidthIntProperty", typeof(int), typeof(MainWindow), new UIPropertyMetadata(0, null));
int WidthInt
{
get { return (int)this.GetValue(WidthIntProperty); }
set { this.SetValue(WidthIntProperty, value); }
}
...
Binding bind = new Binding("Text");
bind.Source = TestHeight;
bind.Mode = BindingMode.TwoWay;
this.SetBinding(MainWindow.HeightIntProperty, bind);
testWindow.SetBinding(Window.HeightProperty, bind);
или если я выполню привязку непосредственно между свойством text и свойством ширины и использую BindingMode.OneWay или наоборот.
Использование профилировщика CLR, кажется, не показывает мне, что выделяется, и у меня нет доступа к коммерческому профилировщику памяти. Может кто-нибудь объяснить мне, что хранится в памяти и как я могу от нее избавиться, сохраняя при этом функциональность непрерывного BindingMode? Должен ли я реализовать свой собственный метод привязки и обрабатывать события самостоятельно? Или есть что-то, что я могу регулярно смывать за пределами GC?
Спасибо за ваше время.