.net MEF保留非共享IDisposable部分的引用,不允许GC收集它们
我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序内存泄漏 我的应用程序导出视图和视图模型时,.net MEF保留非共享IDisposable部分的引用,不允许GC收集它们,.net,memory-leaks,prism,mef,object-lifetime,.net,Memory Leaks,Prism,Mef,Object Lifetime,我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序内存泄漏 我的应用程序导出视图和视图模型时,PartCreationPolicy设置为CreationPolicy.NonShared。视图和视图模型分别继承自ViewBase和ViewModelBase,后者实现了IDisposable 现在,由于我的部件实现了IDisposable,容器保留了对它们的引用,这导致垃圾收集器不会释放它们。根据设计,这是: 除非满足以下条件之一,否则容器将不包含对其创建的零件的引用: 零件标记
PartCreationPolicy
设置为CreationPolicy.NonShared
。视图和视图模型分别继承自ViewBase
和ViewModelBase
,后者实现了IDisposable
现在,由于我的部件实现了IDisposable
,容器保留了对它们的引用,这导致垃圾收集器不会释放它们。根据设计,这是:
除非满足以下条件之一,否则容器将不包含对其创建的零件的引用:
- 零件标记为
共享
- 该部件实现了
IDisposable
- 一个或多个导入配置为允许重新编译
IDisposable
上述文章中讨论的两种策略对我来说似乎都不是好的解决方案:
需要一个ReleaseExport
对象作为参数,我不知道如何提供。我有我的视图的实例,但是我无法知道创建视图所使用的契约是什么。如果Export
有一个重载,它可以接收容器创建的任何对象,那就太好了ReleaseExport
- 使用子容器似乎也不是一个自然的选择
任何帮助都将不胜感激。当您实现
IDisposable
时,您的意思是应该以确定的方式清理类型(通过调用IDisposable.Dispose
,而不是在垃圾回收器决定时间到了时随机清理)
在您的情况下,视图模型只有在您处理容器时才会被处理,这可能不是您想要做的。为了解决这个问题,我看到了两种可能的解决方案:
- 不要在您的视图模型上实现
。显然,您并不关心它们何时被清理,那么为什么要将它们设置为IDisposable
IDisposable
- 您可以使用共享视图模型工厂类,而不是让容器创建每个非共享视图模型。然后,您可以将该类注入视图模型的所有者,以允许所有者显式创建视图模型。假定这些所有者也知道何时处置视图模型
基本上,如果某个实例是一次性的,那么在您的代码中也应该是一个合理的点,在这里您需要处理一次性的内容。您应该通过导入的来创建这些实例。然后,您将拥有必要的控制权,可以通过
ExportLifetimeContext.dispose()来处理它们。
但是,这仅在下一个.NET版本(4.5)或codeplex上的最新MEF预览版本中提供。(在旧版本的MEF中,相同的功能作为示例实现,称为PartCreator,如本节所述。)除非Prism支持视图对象的某种生存期,否则这里没有解决方案,除非从视图公开的接口列表中删除
IDisposable
有三种MEF方法来处理此问题,其他响应者都提到了这三种方法:
ExportFactory
- 子容器
ReleaseExport()
ReleaseExportedObject()
,因为多个(例如属性)导出可以返回相同的值;从逻辑上讲,可以提供相同的值,但增加的复杂性使得MEF在可预见的未来不太可能解决此问题
希望这能有所帮助;我重新标记了这个问题“prism”,因为我相信prism社区中的其他人也会遇到这个问题,并且能够提供建议。所有其他答案都提供了很好的方法来回避这个问题,但我最终使用的是我自己的自定义界面,
ICleanup
,而不是IDisposable
。这当然可能不适合所有人。我相信你会同意,我实现IDisposable
是有点愚蠢,因为我的虚拟机上实现了MEF容器,所以我早一点而不是晚一点处理一个对象,并实现了完全相反的效果。不实现IDisposable
,这不是一个错误eal选项,因为我需要像从复合命令中注销一样进行清理-如果我不这样做,虚拟机将不会被GC’d。我的视图负责处理它们的虚拟机,但无论如何调用Dispose()
不会从容器中删除对对象的引用,因此无论如何也不会有帮助。我认为,使用我的第二个建议,即在每个视图中注入视图模型工厂,而不是MEF创建的视图模型,应该可以解决您的问题。显然,为每个视图模型创建工厂会变得相当乏味,但这就是问题所在我发现自己在使用当前版本的MEF进行依赖项注入时做了很多工作。我在问题中没有提到它,但我使用Prism创建视图,因此我无法访问代码的这一部分来检索ExportFactory
对象。即使可以,也存在从中的位置访问factory对象的问题在要处理视图的位置编码,并对每个非共享的文件使用ExportFactory