【问题标题】:memory leaks in WPF MVVM Prism appWPF MVVM Prism 应用程序中的内存泄漏
【发布时间】:2012-04-30 18:31:09
【问题描述】:

我有一个使用 MVVM Prism 编写的 WPF 应用程序。它有很多标签。这些选项卡每个消耗大约 2..3 MB 的内存。客户抱怨说,在打开和关闭几十个选项卡后,应用程序消耗的内存比一开始时要多得多。此外,打开新标签页需要更多内存,因此应用程序不会使用旧标签页而是创建新标签页。

很明显旧标签不会被垃圾回收。显然是因为有一些链接指向它们。

如何以任何方式对它们进行垃圾收集?我应该只实现 IDisposable,并删除所有可能的引用吗?并确保在析构函数中也调用了 Dispose 方法?我不确定是否可以删除所有不需要的引用。

也许我可以使用一个很好的工具来帮助我解决这个问题?

【问题讨论】:

  • “显然是因为有一些链接指向它们”可能不是真的。如果 GC 感觉不像垃圾收集,即使没有引用,它们也会留在内存中。
  • @stijn 我已经调用了 GC.Collect,但它们仍然留在内存中。

标签: .net wpf memory-leaks garbage-collection prism-4


【解决方案1】:

这显然是一个加载的问题。内存消耗可能不仅是由内存泄漏引起的!每个应用程序都是不同的,并且没有灵丹妙药,所以这里有一些可能会有所帮助的想法。

  1. 获取 ANTS 分析器,它有 2 周的试用期 + 很棒的教程。它会为您指出很多东西,例如僵尸对象等。

  2. WPF 是一头猪,因此您打开的选项卡(不会消失的控件)越多,占用的内存就越多。看看你的 XAML,你能把它修整一下。例如,使用 TextBlock 代替标签。删除额外的嵌套控件,例如 StackPanel 中的 StackPanel 或 Grid 中的 Grid,在 stackpanel 中 - 将所有这些控件放在一个网格中,并使用行/列。它很复杂,尝试改变它。例如,如果在焦点上它在项目周围画了一个边框并做了一些花哨的事情,问一个问题,我可以从每个项目中删除它,并创建一个控件来计算它的位置并适当地放置自己。

  3. 每个选项卡是否有相同类型的视图(用户控件或控件),只是不同的实例?如果是这样,您可以回收它们吗?一年多以前,我在一个项目中,我们有一些菜单为一些标准创建一个选项卡,然后是另一个,另一个。标准不同,但视图类型相同。它只是被注入了不同的信息——Prism 正在为每个选项卡创建一个新的视图控件,这显然很昂贵。我们最终做的是创建不同的 ViewModel,但保留该昂贵视图的相同实例(通过在需要时删除/添加回该区域来回收)。 为此,每个 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. 垃圾回收注意事项: .NET 垃圾收集器的全部目的是代表我们管理内存。 但是,在一些非常罕见的情况下,使用 GC.Collect() 以编程方式强制垃圾收集可能是有益的。

    具体来说:

    a.当您的应用程序即将进入您不希望被可能的垃圾回收中断的代码块时。

    b.当您的应用程序刚刚完成分配大量对象并且您希望尽快删除尽可能多的获取内存时。 (我的项目就是这种情况)

    c。还有:http://blogs.msdn.com/b/ricom/archive/2004/11/29/271829.aspx

我肯定会在每个 ViewModel 上实现 Dispose 方法,在其中我会将所有 big 设置为 null,不要忘记取消订阅事件以及计时器之类的东西。你可以调用 GC.Collect ();但请阅读上面的注释。不要忘记清理复杂对象,不要只是将它们设置为空。例如,在我的 Dispose 中,我们有类似的内容:

ClearDisplayGrid ();

这反过来又是这样做的:

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

【讨论】:

  • 我使用了 ANTS 内存分析器,发现有一些类引用了一些视图的对象。这些引用会导致视图和 ViewModel 不被收集。我还没有解决它,但知道真正的问题会使问题完全不同。
猜你喜欢
  • 2010-12-23
  • 2010-11-27
  • 2011-03-21
  • 1970-01-01
  • 1970-01-01
  • 2016-03-15
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多