Что лучший способ состоит в том, чтобы избежать утечек памяти в приложении WPF PRISM/MVVM

TeX:

\def~{~.}~

Результаты в:

! TeX capacity exceeded, sorry [input stack size=5000].
~->~
    .
~->~
    .
~->~
    .
~->~
    .
~->~
    .
~->~
    .
...
<*> \def~{~.}~

ЛАТЕКС:

\end\end

Результаты в:

! TeX capacity exceeded, sorry [input stack size=5000].
\end #1->\csname end#1
                      \endcsname \@checkend {#1}\expandafter \endgroup \if@e...
<*> \end\end
13
задан Dave Clemmer 31 August 2011 в 17:52
поделиться

2 ответа

Я могу сказать вам, что я испытал 100% боли, которую вы испытали. Я думаю, мы братья по утечке памяти.

К сожалению, единственное, что я придумал здесь, это нечто очень похожее на то, что вы думаете.

Мы создали присоединенное свойство, которое представляет собой представление может применяться к себе для привязки обработчика к ViewModel:

<UserControl ...
             common:LifecycleManagement.CloseHandler="{Binding CloseAction}">
...
</UserControl>

Тогда наша ViewModel просто имеет на нем метод типа Action:

public MyVM : ViewModel
{
     public Action CloseAction
     {
          get { return CloseActionInternal; }
     }

     private void CloseActionInternal()
     {
          //TODO: stop timers, cleanup, etc;
     }
}

Когда срабатывает мой метод close (у нас есть несколько способов сделать это ... это TabControl UI с «X» в заголовках вкладок и тому подобное), я просто проверяю, зарегистрировалось ли это представление в AttachedProperty. Если это так, я вызываю метод, на который здесь есть ссылка.

It ' Это довольно окольный способ просто проверить, является ли DataContext представления IDisposable, но в то время это было лучше. Проблема с проверкой DataContext заключается в том, что у вас могут быть модели подвидов, которым также нужен этот элемент управления. Вам нужно либо убедиться, что ваши модели представления пересылают этот вызов dispose, либо проверить все представления на графике и посмотреть, являются ли их тексты данных IDisposable (тьфу).

Мне кажется, что здесь чего-то не хватает. Есть несколько других платформ, которые пытаются смягчить этот сценарий другими способами. Вы можете взглянуть на Caliburn . У него есть система для обработки этого, где ViewModel знает все модели подвидов, и это позволяет ему автоматически связывать вещи вперед. В частности, есть интерфейс ISupportCustomShutdown (думаю, вот что это такое) s), который помогает смягчить эту проблему.

Однако лучшее, что я сделал, - это убедился и использовал хорошие инструменты утечки памяти, такие как Redgate Memory Profiler, которые помогают визуализировать граф объектов и находить корневой объект. Если вы смогли определить эту проблему с DispatchTimer, я полагаю, вы уже это делаете.

Изменить: Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Однако мы сделали, чтобы убедиться и использовать хорошие инструменты утечки памяти, такие как Redgate Memory Profiler, которые помогут вам визуализировать граф объекта и найти корневой объект. Если вы смогли определить эту проблему с DispatchTimer, я полагаю, вы уже это делаете.

Изменить: Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Однако мы сделали, чтобы убедиться и использовать хорошие инструменты утечки памяти, такие как Redgate Memory Profiler, которые помогут вам визуализировать граф объекта и найти корневой объект. Если вы смогли определить эту проблему с DispatchTimer, я полагаю, вы уже это делаете.

Изменить: Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Обязательно используйте хорошие инструменты для утечки памяти, такие как Redgate Memory Profiler, которые помогут вам визуализировать граф объекта и найти корневой объект. Если вы смогли определить эту проблему с DispatchTimer, я полагаю, вы уже это делаете.

Изменить: Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Обязательно используйте хорошие инструменты для утечки памяти, такие как Redgate Memory Profiler, которые помогут вам визуализировать граф объекта и найти корневой объект. Если вы смогли определить эту проблему с DispatchTimer, я полагаю, вы уже это делаете.

Изменить: Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

Я забыл одну важную вещь. Возможна утечка памяти, вызванная одним из обработчиков событий в DelegateCommand. Вот ветка об этом на Codeplex, в которой это объясняется. http://compositewpf.codeplex.com/WorkItem/View.aspx?WorkItemId=4065

В последней версии Prism (v2.1) это исправлено. ( http://www.microsoft.com/downloads/details.aspx?FamilyID=387c7a59-b217-4318-ad1b-cbc2ea453f40&displaylang=en ).

14
ответ дан 2 December 2019 в 00:03
поделиться

Мои выводы на данный момент ...

В дополнение к PRISM, Unity, WPF и MVVM мы также используем Entity Framework и сетку данных Xceed. Профилирование памяти было выполнено с помощью dotTrace.

В итоге я реализовал IDisposable в базовом классе для моих моделей представления, при этом метод Dispose (bool) был объявлен виртуальным, что позволило подклассам также выполнить очистку. Поскольку каждая модель представления в нашем приложении получает дочерний контейнер из Unity, мы также удаляем его, в нашем случае это гарантирует, что объектный контекст EF вышел за пределы области видимости. Это было нашим основным источником утечек памяти.

Модель представления размещена в явном методе CloseView (UserControl) в базовом классе контроллера. Он ищет IDisposable в DataContext представления и вызывает для него Dispose.

Сетка данных Xceed, похоже, является причиной значительной доли утечек, особенно в долго работающих представлениях. Любое представление, обновляющее ItemSource сетки данных путем присвоения новой коллекции, должно вызывать Clear () для существующей коллекции перед назначением новой.

Будьте осторожны с Entity Framework и избегайте любых длительных контекстов объектов. Когда дело касается больших коллекций, это очень беспощадно, к ресурсу, содержащему CellEditor, ресурс снова будет содержать ссылку на ячейку, используя x: Shared = "False", чтобы каждый раз получать новую копию, при этом старая удаляется правильно.

Будьте осторожны, когда привязка DelegateCommand к элементам в сетке данных Exceed, если у вас есть такой случай, как кнопка удаления в строке, которая связывается с командой, обязательно очистите коллекцию, содержащую ItemsSource, перед закрытием представления. Если вы обновляете коллекцию, вам также необходимо повторно инициализировать команду, так как команда будет содержать ссылку на каждую строку.

Будьте осторожны при привязке DelegateCommand к элементам в таблице данных Exceed; если у вас есть случай, например кнопка удаления в строке, которая привязана к команде, обязательно очистите коллекцию, содержащую ItemsSource, перед закрытием представления. Если вы обновляете коллекцию, вам также необходимо повторно инициализировать команду, так как команда будет содержать ссылку на каждую строку.

Будьте осторожны при привязке DelegateCommand к элементам в таблице данных Exceed; если у вас есть случай, например кнопка удаления в строке, которая привязана к команде, обязательно очистите коллекцию, содержащую ItemsSource, перед закрытием представления. Если вы обновляете коллекцию, вам также необходимо повторно инициализировать команду, так как команда будет содержать ссылку на каждую строку.

2
ответ дан 2 December 2019 в 00:03
поделиться
Другие вопросы по тегам:

Похожие вопросы: