zoukankan      html  css  js  c++  java
  • MEF等Ioc框架引起内存泄露-PartCreationPolicy

    对象的创建可以使用new,也可以使用IOC架如:castle、MEF等,IOC创建的对象的生命周期,可能IOC负责管理,使用框架的开发者如果不弄清楚可能会造成内存泄露问题。

    这些内存泄露问题并不是IOC框架的bug,只是开发者使用不当或者不注意造成的内存泄露问题。

    以MEF为例说明我碰到的两种内存泄露问题。

    内存泄露系列阅读提示:

    一摸一样的对象图,有时候我们可以认为它是内存泄露,有时候又认为它不是内存泄露,这一切只是由于上下文不同,这一系列文章中ANTS Memoery Profle截图都是有特定上下文,单独看完全没有意义。如何确定是内存泄露?可以参考前面的文章。

    对象以图的形式存在,Ants Memory Profile为了分析方便把这些图处理为树,让我们可以把注意力集中到分析的对象。但我们必须明白内存中对象关系构成图,也就是说ANTS的树状图只是内存中对象分布的一个局部,分析内存泄露时必须有全局观念,需要相关的几张图一起看,即使一张图也要整体看,这样才能分析内存泄露问题。

    由于看一张图没什么意义,如果把多张图都贴出来,这文章就太难写了,即使多张图都贴出来,也不一定能表达清楚,分析内存泄露最重要的是经验。接下来的几篇会减少甚至不用这ANTS图。

    PartCreationPolicy使用不当引起内存泄露

    Shared:对象以Singleton方式创建。

    Non Shared:每次请求时创建新对象。

    Any Be default, CompositionContainer will use Shared, unless the ComposablePart or importer requests NonShared。默认值

    在使用不同的组合方式时,PartCreationPolicy有不同的默认值,因此尽量不要使用默认值。

    看下面的程序:

    NavigationCommand:由于多个View页面都有需要导航,把导航都放到类NavigationCommand中,恰恰是这一做法引出了内存泄露问题。

    1
    <div class="cnblogs_code"><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div><div><span style="color: #000000;">[Export(</span><span style="color: #0000FF;">typeof</span><span style="color: #000000;">(NavigationCommand))]<br><br></span><span style="color: #0000FF;">public</span><span style="color: #000000;"> </span><span style="color: #0000FF;">class</span><span style="color: #000000;"> NavigationCommand<br><br>{<br><br></span><span style="color: #0000FF;">private</span><span style="color: #000000;"> RelayCommand</span><span style="color: #000000;"><</span><span style="color: #0000FF;">string</span><span style="color: #000000;">></span><span style="color: #000000;"> readBookComamand </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">;<br><br></span><span style="color: #0000FF;">public</span><span style="color: #000000;"> RelayCommand</span><span style="color: #000000;"><</span><span style="color: #0000FF;">string</span><span style="color: #000000;">></span><span style="color: #000000;"> ReadBookComamand<br><br>{<br><br></span><span style="color: #0000FF;">get</span><span style="color: #000000;"><br><br>{<br><br></span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (navigatToContentCommand </span><span style="color: #000000;">==</span><span style="color: #000000;"> </span><span style="color: #0000FF;">null</span><span style="color: #000000;">)<br><br>{<br><br>navigatToContentCommand </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> RelayCommand</span><span style="color: #000000;"><</span><span style="color: #0000FF;">string</span><span style="color: #000000;">></span><span style="color: #000000;"><br><br>(<br><br>p </span><span style="color: #000000;">=></span><br><br>{<br><br><font class="Apple-style-span" color="#008000">//<br></font>},<br><br>p <span style="color: #000000;">=></span><span style="color: #000000;"> </span><span style="color: #000000;">!</span><span style="color: #0000FF;">string</span><span style="color: #000000;">.IsNullOrWhiteSpace(p)<br><br>);<br><br>}<br><br></span><span style="color: #0000FF;">return</span><span style="color: #000000;"> readBookComamand;<br><br>}<br><br>}<br><br>}</span></div><div class="cnblogs_code_toolbar"><span class="cnblogs_code_copy"><a href="javascript:void(0);" onclick="copyCnblogsCode(this)" title="复制代码"><img src="http://common.cnblogs.com/images/copycode.gif" alt="复制代码"></a></span></div></div>

    ViewModle

    复制代码
    [ViewModelExport(typeof(BookPageSearcheViewModle), "BookPageSearche")]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class BookPageSearcheViewModle: NavViewModel
    {
    public RelayCommand<string> ReadBookComamand
    {
    get
    {
    return NavigationCommand. ReadBookComamand;
    }
    }
    }
    public abstract class NavViewModel : ViewModelBase, IViewModel
    {
    /// <summary>
    /// The navigation service allows you to navigate to an other ViewModel.
    /// </summary>
    [Import]
    public INavigationService NavigationService { get; set; }
    [Import]
    public NavigationCommand NavigationCommand
    {
    get;
    set;
    }
    }
    复制代码

    View

    复制代码
    [ViewExport(ViewModelContract = typeof(BookPageSearcheViewModle))]
    public partial class BookPageSearcheView: Page, IView
    {
    public BookPageSearcheView ()
    {
    InitializeComponent();
    }
    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
    if (this.DataContext is ICleanup)
    {
    ((ICleanup)this.DataContext).Cleanup();
    }
    }
    }
    }
    复制代码

    上例中NavigationCommand默认以Shared方式创建。

    ANTS Memory Profiel 产生内存泄露的对象图:

    5

    可看出:BookPageSearcheViewModle 、Mef都引用了NavigationCommand,导致NavigationCommand没有被释放产生了内存泄露,在此只看MEF这一条路径。

    我在处理这个内存泄露时太专注于BookPageSearcheViewModle对readBookCommand的引用了,而没有全面看这些图,断开BookPageSearcheViewModle对readBookCommand引用是最简单的处理方法,但是在处理其他ViewModel的时候会发现太多的Command需要处理,这时候才认识到断开引用的点错了。

    因此一定要谨慎全面的看对象图,一个路径上包含n个点,断开任何点都能解决这个对象的泄露问题,但是一个程序有N个对象,这种只着眼当前对象的处理方式不能从根本上解决问题,必须找到内存泄露的根源

    clip_image002

    解决MEF这个泄露问题,最简单的是加上:[PartCreationPolicy(CreationPolicy.NonShared)]

    还可以使NavViewModel类实现所有Command,把组合转换为继承,断开长引用。

    结论

    a) 不要盲目使用第三方框架。

    b) 设计时组合优先于继承,但组合更容易产生内存泄露,因为任何一方如果是长时间存活,内存就不会被释放。继承则无这个问题。

    c) 注意由IOC创建的对象生命周期,如果IOC创建的对象由容器管理生命期,可能需要调用IOC提供的相关方法执行对象的销毁。

    e)MVVM 比Code behind 方式更容易产生内存问题。V、VM双向引用关系,更可能造成内存不被释放

    http://www.cnblogs.com/bluewater/archive/2011/04/14/2016288.html

  • 相关阅读:
    delphi datetimepicker 修改时间无效问题
    C#写入文件
    C# winform中listview排序
    C/C++,python,java,C#月经贴问题
    Redis Sentinel 原理简单介绍
    JVM垃圾收集 知识汇总
    Java HotSpot VM Options
    Spring三级缓存解决循环依赖
    Markdown基础用法
    join示例分析
  • 原文地址:https://www.cnblogs.com/tianciliangen/p/4964735.html
Copyright © 2011-2022 走看看