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 产生内存泄露的对象图:

可看出: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

时间: 2024-12-20 01:56:44

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

MEF引起的内存泄露

也许你编程的时候很小心,注意不引起内存泄露,例如不要被全局Static的变量引用上,注意Singleton的static引用,注意Event Handler注销,注意IDisposable接口实现,而且正确实现了IDisposable.但或许你还是有内存泄露,为何?因为你的IDisposable接口根本没有被触发!为什么?参考MSDN这个页面的”Dispose method not invoked ”章节.还有其它的内存泄露原因,比如第三方组件或框架,框架本身的内存泄露问题,已经框架本身有Lif

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

增加方式如下:web.xml中加入  <listener>    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>  </listener>  org.springframework.web.util.IntrospectorCleanupListener源代码中对其的解释如下:  在Web应用程序关闭时IntrospectorC

PHP的高效IOC框架——CanoeDI

PHP的高效IOC框架--CanoeDI 一个非常简单且实用的IoC框架,相对于其他的Ioc框架有如下特点: 高效: 框架使用了非常实用且高效的算法,使得框架本身对应用的影响微乎其微,且框架提供了C扩展,最大限度的将性能提升到最高. 配置简单: 大多数情况下几乎不需要额外的配置 自动装配: 基于PHPDocument的property属性来自动装配 懒加载: 所有被注入的变量的实例都为即用即取, 不会产生内存垃圾 IDE友好: 因为利用的是PHP的标准规范, 兼容大部分IDE 安装 编译安装,可

JAVA 内存泄露详解(原因、例子及解决)

转载请注明出处:http://blog.csdn.net/anxpp/article/details/51325838,谢谢! Java的一个重要特性就是通过垃圾收集器(GC)自动管理内存的回收,而不需要程序员自己来释放内存.理论上Java中所有不会再被利用的对象所占用的内存,都可以被GC回收,但是Java也存在内存泄露,但它的表现与C++不同. JAVA 中的内存管理 要了解Java中的内存泄露,首先就得知道Java中的内存是如何管理的. 在Java程序中,我们通常使用new为对象分配内存,而

Unix下C程序内存泄露检测工具:valgrind的安装使用

Valgrind是一款用于内存调试.内存泄漏检测以及性能分析的软件开发工具. Valgrind的最初作者是Julian Seward,他于2006年由于在开发Valgrind上的工作获得了第二届Google-O'Reilly开源代码奖. Valgrind遵守GNU通用公共许可证条款,是一款自由软件. Valgrind的安装和使用 去官网www.valgrind.org下载最新版本的valgrind,我这里下载的是valgrind 3.11.0.tar.bz2. #tar xvf valgrind

Android中Handler引起的内存泄露

在Android常用编程中,Handler在进行异步操作并处理返回结果时经常被使用.通常我们的代码会这样实现. 但是,其实上面的代码可能导致内存泄露,当你使用Android lint工具的话,会得到这样的警告 In Android, Handler classes should be static or leaks might occur, Messages enqueued on the application thread’s MessageQueue also retain their t

APNS开源包的内存泄露问题

APNS(全称:Apple Push Notification Service),主要是用于往苹果设备推送push消息通知! 基本流程: 今天要聊的问题集中在第4个环节,我们自己的服务器往苹果的消息中心推送通知. 现状: 历史原因,push的代码散落在各个应用中,随着新消息通道不断接入,开发.维护成本较高,开始考虑构建push中心, 封装dubbo接口对外提供服务,对外屏蔽各种差异,将所有的push业务逐步收扰到push中心. 过程漫长,开始接入的是个人业务,每天的调用量不大,服务器还表现正常:

如何解决python训练数据内存泄露问题?

Python语言 越来越广泛的应用于机器学习/ 深度学习领域,是目前最火的该领域编程语言,各大深度学习框架基本都支持 python 接口. 在TensorFlow 训练模型的过程中,一般数据加载分情景各有不同. 1.  当数据量能直接全部载入内存时,当然最是方便,直接全部载入内存,然后训练即可. 2.  数据无法全部载入内存时,有多种方法.介绍其中 2 种用的多的,其一是边训练边读取(可以用多线程进行优化),其二是随机打乱所有训练数据的索引然后随机选择部分数据进行训练测试. 第2 类情景中,有可

内存泄露之常见问题解决--初级篇

身为一个段子猿,我决定来写写最近的学习心得. 1.简介 在整个Android开发过程中,内存泄露是导致OOM的一个重点因素.大概意思就是:GC无法回收原本应该被回收的对象,这个对象就引发了内存泄露.那有什么危害呢?手机的内存大小是有限的,如果不能释放的话,你就无法创建新的对象,你的新界面等等就无法正常运行,然后程序就OOM了(OutOfMemory). 2.OOM以及内存泄露 OOM通俗点讲就是,你家里有2个厕所,本来你和你老婆用的话,都是够用的,有一天你不小心造人了,从此家里有了1+1=3个人