2012-04-19 2 views
2

У меня есть приложение WPF, написанное с использованием MVVM Prism. В нем много вкладок. Эти вкладки потребляют около 2,3 МБ памяти. Клиент жалуется, что после открытия и закрытия нескольких десятков вкладок приложение потребляет гораздо больше памяти, чем с самого начала. Кроме того, для открытия новых вкладок требуется больше памяти, поэтому приложение не использует старые вкладки и вместо этого создает новые.утечки памяти в WPF MVVM Призматическое приложение

Таким образом, очевидно, что старые вкладки не собираются с мусором. Очевидно, потому что есть некоторые ссылки, указывающие на них.

Как я мусор-собираю их в любом случае? Должен ли я просто реализовать IDisposable и удалить все ссылки на все, что возможно? И убедитесь, что метод Dispose также вызывается в деструкторе? Я не уверен, что смогу удалить все необработанные ссылки.

Возможно, есть хороший инструмент, который я могу использовать, что может помочь мне с этой проблемой?

+0

«Очевидно, потому что есть некоторые ссылки, указывающие на них» может не быть правдой. Если GC не чувствует, как сбор мусора, они остаются в памяти, даже если ссылок нет. – stijn

+0

@stijn Я назвал GC.Collect, но они все еще остались в памяти. –

ответ

4

Это явно загруженный вопрос. Потребление памяти может быть связано не только с утечками памяти! Каждое приложение отличается, и нет серебряной пули, поэтому здесь есть некоторые идеи, которые могут помочь.

  1. получить профилировщик ANTS, он имеет пробный период 2 недели + отличные уроки. Это укажет вам на множество вещей, таких как объекты zomby и т. Д.

  2. WPF - это свиньи, поэтому чем больше вкладок вы открываете (элементы управления, которые не исчезают), тем больше памяти он будет принимать. Посмотрите на свой XAML, можете ли вы его обрезать. Например, используйте TextBlock вместо меток. Удалите дополнительные вложенные элементы управления, такие как StackPanel внутри StackPanel или Grid внутри Grid, внутри панели стека - поместите все те в одну сетку и используйте строку/столбцы. Если у вас есть шаблон элемента, в котором каждый элемент делает что-то, что делает это сложно, попробуйте изменить это. Например, если в фокусе он рисует границу вокруг элемента и делает что-то фантастическое, задайте вопрос, могу ли я удалить это из каждого элемента и создать один элемент управления, который вычисляет его местоположение и размещает сам по себе.

  3. У вас есть представления (пользовательские элементы управления или элементы управления) для каждой вкладки того же типа, только для другого экземпляра? Если это так, вы можете их переработать? Я был в проекте год назад, когда у нас было какое-то меню, создающее вкладку для некоторых критериев, а затем еще и другое. Критерии были разными, но тип вида был одинаковым. Это просто вводилось с различной информацией - Prism создавал новый элемент управления View для каждой из этих вкладок, что, очевидно, дорого. То, что мы закончили, - это создание разных ViewModels, но сохранение одного и того же экземпляра (утилизация путем удаления/добавления обратно в случае необходимости в регион) этого дорогого вида. Для этого каждый ViewModel бы по судоходству (образец)

    //detaching from Prism region allows for recycling 
    public override void OnNavigatedFrom (NavigationContext navigationContext) 
    { 
    var view = _container.Resolve (typeof (Object), "NameOfTheView"); 
    if (view != null) 
        navigationContext.NavigationService.Region.Remove (view); 
    } 
    //similarly you can readd it where your think it is nedded.. 
    
    public override void OnNavigatedTo (NavigationContext navigationContext) 
    { 
        base.OnNavigatedTo (navigationContext); 
        RestoreDataState (_state); 
    

    }

    эта связь может быть полезно: http://blogs.msdn.com/b/dphill/archive/2011/01/23/closable-tabbed-views-in-prism.aspx

  4. Обратите внимание на Garbage Collection: Вся цель .NET сборщик мусора должен управлять памятью от нашего имени. Однако в некоторых очень редких случаях может быть полезно программно принудительно собрать мусор с помощью GC.Collect().

    В частности:

    A.When ваше приложение собирается войти в блок кода, который вы не хотите, прерываемой возможной сборки мусора.

    b.Когда ваше приложение только что закончило выделение чрезвычайно большого количества объектов, и вы хотите как можно скорее удалить как можно больше приобретенной памяти. (это было в моем проекте)

    c. также: http://blogs.msdn.com/b/ricom/archive/2004/11/29/271829.aspx

Я определенно реализовать методы Dispose на каждом ViewModel, где я хотел бы установить все большую пустое значение, не забудьте отписаться от событий, и такие вещи, как таймеры. Вы можете вызвать GC.Collect(); но прочитайте вышеприведенную записку. Не забудьте очистить сложный объект, не просто установите для них значение null. Например, в моем Dispose у нас было что-то вроде:

ClearDisplayGrid(); 

, который, в свою очередь делает это:

private void ClearDisplayGrid() 
    { 
     foreach (var r in DisplayGrid.MyItems.SelectMany (it => it.SubItems)) 
     { 
      r.IsSelectedChanged -= ReadingIsSelectedChanged; 
      r.InEditChanged -= ReadingInEditChanged; 
      r.PropertyChanged -= ReadingPropertyChanged; 
     } 
    } 
+0

Я использовал профилировщик памяти ANTS и выяснил, что есть некоторые классы, ссылающиеся на объекты некоторых представлений. Эти ссылки не позволяют собирать представления и ViewModels. Я еще не исправил его, но знание реальной проблемы делает проблему совершенно другой. –

+0

очень здорово, я да, ANTS действительно зарекомендовал себя для меня –

Смежные вопросы