До сих пор мое тестирование показано, что все стандартные подходы, примеры и платформы, использующие шаблон MVVM в silverlight, страдают от огромной проблемы: массивных утечек памяти, которые препятствуют сборке мусора для виртуальных машин.
Очевидно, что это громадное и нелепое утверждение— так что я ожидаю, что кто-то даст очевидный ответ, почему и где я ошибаюсь :)
Шаги для воспроизведения просты:
Это создает цепочку ссылок, которая простирается от корня до BindingExpression и вашей модели представления. Затем вы можете удалить представление из дерева пользовательского интерфейса, а также все ссылки на виртуальную машину, однако виртуальная машина никогда не будет удалена сборщиком мусора благодаря цепочке ссылок rootBindingExpressionVM.
Я создал два примера, иллюстрирующих проблему. У них есть кнопка для создания нового представления/модели представления (которая должна сбрасывать все ссылки на старые) и кнопка, которая вызывает сборку мусора и сообщает о текущем использовании памяти.
Пример 1 представляет собой сверхупрощенный микропример калиберна. Пример 2 не использует никаких фреймворков и просто иллюстрирует проблему самым простым способом, который я мог придумать.
Для тех, кто хочет помочь, но не хочет загружать примеры проектов, вот код примера 2. Начнем с модели представления под названием FooViewModel:
public class FooViewModel : INotifyPropertyChanged
{
string _fooText;
public string FooText
{
get { return _fooText; }
set
{
_fooText = value;
NotifyPropertyChanged("FooText");
}
}
private byte[] _data;
public FooViewModel()
{
_data = new byte[10485760]; //use up 10mb of memory
}
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Он просто предоставляет строковое свойство с именем FooText, которое мы также привяжем. INotifyPropertyChanged необходим для облегчения привязки.
Затем у нас есть представление с именем FooView, которое представляет собой пользовательский элемент управления, содержащий:
(пространства имен опущены для краткости)
Важным моментом здесь является текстовое поле, которое привязано к свойству FooText. Конечно, нам нужно установить контекст данных, который я решил сделать в отделенном коде, а не вводить ViewModelLocator:
public partial class FooView : UserControl
{
public FooView()
{
InitializeComponent();
this.DataContext = new FooViewModel();
}
}
MainPage выглядит следующим образом:
со следующим кодом:
private void Button_Click(object sender, RoutedEventArgs e)
{
myContent.Content = new FooView();
}
private void Button2_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show("Memory in use after collection: " + (GC.GetTotalMemory(true) / 1024 / 1024).ToString() + "MB");
}
Примечание. воспроизведите проблему, обязательно введите что-нибудь в текстовое поле, так как я считаю, что выражение привязки не создается до тех пор, пока оно не понадобится.
Стоит отметить, что эта статья базы знанийможет быть связана с этим, однако я не уверен, поскольку обходной путь «метода 2», похоже, не имеет эффекта, а цепочка ссылок, похоже, не соответствовать.
Кроме того, я не уверен, что это имеет значение, но я использовал CLR Profilerдля диагностики причины.
Обновление:
Если кто-то хочет протестировать и сообщить о своих выводах в комментариях, я размещаю приложение Silverlight через Dropbox здесь: Размещенный пример.Чтобы воспроизвести: нажмите верхнюю кнопку, введите что-нибудь, нажмите верхнюю кнопку, введите что-нибудь, нажмите верхнюю кнопку. Затем нажмите кнопку. Если он сообщает об использовании 10 МБ (или, возможно, о каком-то другом объеме, который не увеличивается), вы не испытываете утечки памяти.
На данный момент проблема возникает на ВСЕХ наших компьютерах для разработки, а именно ThinkPad w510 (43192RU) с 12 ГБ оперативной памяти и 64-разрядной ОС Win 7 Enterprise. Сюда входят некоторые, на которых не установлены инструменты разработки. Возможно, стоит отметить, что они работают на рабочей станции VMWare.
Проблема НЕ возникает на других машинах, которые я пробовал, включая несколько домашних ПК и других ПК в офисе. Мы несколько исключили версии SL, объем памяти и, возможно, vmware. До сих пор не установил причину.