MEF保留对NonShared IDisposable部件的引用,不允许GC收集它们

时间:2012-01-09 11:51:50

标签: .net memory-leaks prism mef object-lifetime

我在MEF的部件生命周期中遇到了一些问题,导致我的Prism应用程序中出现内存泄漏。

我的应用程序导出视图和视图模型,PartCreationPolicy设置为CreationPolicy.NonShared。视图和视图模型分别从ViewBaseViewModelBase继承,实现IDisposable

现在,由于我的部件实现了IDisposable,因此容器会保留对它们的引用,这会导致它们不被垃圾收集器释放。根据{{​​3}},这是设计的:

  

除非满足下列条件之一,否则容器将不会保留对其创建的零件的引用:

     
      
  • 该部分标记为Shared
  •   
  • 该部分实现了IDisposable
  •   
  • 配置一个或多个导入以允许重新组合
  •   

那么我怎样才能让MEF不参考这些部分?是否有一个属性可以让MEF知道我不希望它保留对我的部分的引用,即使它实现了IDisposable

上述文章中讨论的两种策略对我来说似乎都不是很好的解决方案:

  • ReleaseExport需要Export个对象作为参数,我不知道如何提供。我有我的观点的实例,但是我无法知道用于创建视图的合同是什么。如果ReleaseExport的重载可以接收容器创建的任何对象,那将会很棒。
  • 使用子容器似乎也不是一种自然的选择。

非常感谢任何帮助。

4 个答案:

答案 0 :(得分:7)

除非Prism支持视图对象的某种生命周期,否则除了从视图公开的接口列表中删除IDisposable之外,这里没有解决方案。

有三种MEF方法可以解决这个问题,其他响应者都提到了这些方法:

  • ExportFactory<T>
  • 儿童容器
  • ReleaseExport()

所有这些都需要在请求原始导出的代码方面做一些工作 - 在这种情况下是Prism中的代码。这是有道理的,因为消费对象的代码不得不知道它是如何以及何时被创建的。

MEF中没有ReleaseExportedObject(),因为多个(例如属性)导出可以返回相同的值;它在逻辑上可能提供,但增加的复杂性使MEF在可预见的未来不太可能解决。

希望这会有所帮助;我已经重新提出这个问题'棱镜',因为我相信Prism社区的其他人会遇到这个并能够提供建议。

答案 1 :(得分:5)

当你实现IDisposable时,你有点说应该以确定的方式清理类型(通过调用IDisposable.Dispose而不是当垃圾收集器确定它是时间时随机清理。

在您的情况下,视图模型将仅在您处置可能不是您想要的容器时处理。为了解决这个问题,我看到了两种可能的解决方案:

  • 请勿在视图模型上实施IDisposable。显然你不关心他们什么时候被清理,为什么要让他们IDisposable

  • 您可以使用共享视图模型工厂类,而不是让容器创建非共享的每个视图模型。然后,您可以将该类注入视图模型的所有者,以允许所有者明确创建视图模型。假设这些所有者也知道何时处置视图模型。

基本上,如果某些东西是一次性的,那么在您需要处理可丢弃的代码时,代码中也应该是一个明智的点。

答案 2 :(得分:4)

您应该通过导入的ExportFactory<T>创建这些实例。然后,您将获得必要的控制权,以通过ExportLifetimeContext<T>.Dispose()处理它们。

但是,这只能在下一个.NET版本(4.5)或在codeplex上的最新MEF预览版本中开箱即用。 (在旧版本的MEF中,相同的功能作为样本实现,并被称为 PartCreator ,如此blog post中所述。)

答案 3 :(得分:2)

所有其他答案提供了绕过这个问题的好方法,但最终我最终做的是使用我自己的自定义界面ICleanup,而不是IDisposable。这当然可能并不适合所有人。