对象的创建可以使用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 产生内存泄露的对象图:

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

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

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

解决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

MEF等Ioc框架引起内存泄露-PartCreationPolicy的更多相关文章

  1. MEF引起的内存泄露

    也许你编程的时候很小心,注意不引起内存泄露,例如不要被全局Static的变量引用上,注意Singleton的static引用,注意Event Handler注销,注意IDisposable接口实现,而 ...

  2. 160715、在web.xml中注册IntrospectorCleanupListener解决Quartz等框架可能产生的内存泄露问题

    增加方式如下:web.xml中加入  <listener>    <listener-class>org.springframework.web.util.Introspect ...

  3. 基于HTML5的WebGL应用内存泄露分析

    上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...

  4. PHP的高效IOC框架——CanoeDI

    一个非常简单且实用的IoC框架,相对于其他的Ioc框架有如下特点: 高效: 框架使用了非常实用且高效的算法,使得框架本身对应用的影响微乎其微,且框架提供了C扩展,最大限度的将性能提升到最高. 配置简单 ...

  5. .Net内存泄露原因及解决办法

    .Net内存泄露原因及解决办法 1.    什么是.Net内存泄露 (1).NET 应用程序中的内存 您大概已经知道,.NET 应用程序中要使用多种类型的内存,包括:堆栈.非托管堆和托管堆.这里我们需 ...

  6. Android 中 Handler 引起的内存泄露

    在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.其实这可能导致内存泄露,代码中哪里可能导致内存泄露,又是如何导致内存泄露的呢?那我们就慢慢分析一下.http://w ...

  7. Android开发笔记——常见BUG类型之内存泄露与线程安全

    本文内容来源于最近一次内部分享的总结,没来得及详细整理,见谅. 本次分享主要对内存泄露和线程安全这两个问题进行一些说明,内部代码扫描发现的BUG大致分为四类:1)空指针:2)除0:3)内存.资源泄露: ...

  8. .NET领域最为流行的IOC框架之一Autofac

    一.前言 Autofac是.NET领域最为流行的IOC框架之一,微软的Orchad开源程序使用的就是Autofac,Nopcommerce开源程序也是用的Autofac. Orchad和Nopcomm ...

  9. 检测内存泄露:Instruments中的Leaks

    前言 如果要检测内存泄露,我们会使用Xcode7自带的Instruments中的Leaks工具来检测. 现在的开发环境是ARC,所以很少会出现内存泄漏的情况. 不过我们一定要养好码代码的规范性. 例如 ...

随机推荐

  1. 如何设置树莓派 -Zero 自启动连接WIFI

    1. 首先我们需要一台可以读取树莓派跟文件系统的Linux虚拟机(比如Ubuntu) 将树莓派SD卡系统插入电脑,识别并打开rootfs文件夹,切换到`rootfs/etc/wpa_supplican ...

  2. 异步任务——AsyncTask的初步认识

    ProgressBar_test.class package com.example.administrator.ten_9; import android.app.Activity; import ...

  3. goaccess安装和使用

    安装依赖 $ sudo apt-get install libncursesw5-dev $ wget https://github.com/maxmind/geoip-api-c/releases/ ...

  4. 【JAVASCRIPT】call和apply的用法以及区别

    function add(c,d){ return this.a + this.b + c + d; } var s = {a:"鸡", b:"你"}; con ...

  5. ajax获取json 格式绑定下拉框

    [{"ClassID":"1","ClassName":"C#","CategorysID":&qu ...

  6. win10 sql server2012 连接navicat 无法使用

    修改 连接navicat时报如下错误,按照网上办法,各种删除navicat的客户端,行不通. 点击sqlserver管理器,提示评估期已过.有关如何升级的测试版软件的信息,请访问http://www. ...

  7. (一)数据库系统概述和ER图

    1.数据库系统 数据库系统有数据库.数据库管理系统.应用系统和数据库管理员组成.数据库呢就是数据的集合,应用系统和管理员就不说了,数据库管理系统即常说的DBMS,比如我们用的mysql,oracle, ...

  8. request_time和upstream_response_time详解

    下图是request_time. 下图是upstream_response_time. 精准的描述就是:request_time是从接收到客户端的第一个字节开始,到把所有的响应数据都发送完为止.ups ...

  9. jquery之闭包

    闭包 常见形式是函数A里面定义一个函数B,并返回函数体的引用,很抽象是不是,具体代码如下: function wenwa() { ; function cj() { console.log(" ...

  10. OkHttp3-基本用法(转)

    OkHttp 一个支持Http和Http/2,可适用于Android以及Java应用的网络请求客户端. 概述 Http是现代网络应用的所常用的协议,它是一种数据传输的媒介.执行高效的Http代码可以让 ...