MEF хранит ссылки на части NonShared IDisposable, не позволяя GC собирать их - PullRequest
11 голосов
/ 09 января 2012

Я столкнулся с некоторой проблемой во время жизни детали MEF, которая вызывает утечки памяти в моем приложении Prism.

Мое приложение экспортирует представления и модели представления с установленным PartCreationPolicy значением CreationPolicy.NonShared.Представления и модели представления наследуются от ViewBase и ViewModelBase соответственно, что реализует IDisposable.

Теперь, поскольку мои детали реализуют IDisposable, ссылка на них сохраняется в контейнере, который вызывает ихне быть выпущенным сборщиком мусора.В соответствии с документацией MEF о времени жизни детали это так:

Контейнер не будет содержать ссылки на детали, которые он создает, если не выполняется одно из следующих условий:

  • деталь помечена как Shared
  • деталь реализует IDisposable
  • Один или несколько импортов сконфигурированы так, чтобы разрешить перекомпоновку

Как я могу заставить MEF не хранить ссылки на эти части?Есть ли атрибут, который я могу использовать, чтобы MEF знал, что я не хочу, чтобы он сохранял ссылку на мою часть, даже если он реализует IDisposable?

Обе стратегии, обсужденные в предыдущей статье, некажутся мне хорошим решением:

  • ReleaseExport требует в качестве параметра объект Export, который я не знаю, как предоставить.У меня есть пример моего представления, но у меня нет возможности узнать, какой контракт использовался для создания представления.Было бы замечательно, если бы была перегрузка для ReleaseExport, которая могла бы получить любой объект, созданный контейнером.
  • Использование дочернего контейнера также не кажется естественным вариантом.

Любая помощь будет принята с благодарностью.

Ответы [ 4 ]

7 голосов
/ 09 января 2012

Если Prism не поддерживает какое-то время жизни для объектов вида, здесь нет решения, кроме как удалить IDisposable из списка интерфейсов, предоставляемых представлением.

Существует три подхода MEF для решения этой проблемы.все упомянутые другими респондентами:

  • ExportFactory<T>
  • Дочерние контейнеры
  • ReleaseExport()

Все они требуют некоторыхработать над частью кода, которая запрашивает исходный экспорт - в данном случае код в Prism.Это имеет некоторый смысл, поскольку для кода, потребляющего объект, нежелательно знать о том, как и когда он был создан.

В MEF нет ReleaseExportedObject(), потому что множественные (например, свойства) экспорты могут возвращатьодинаковое значение;это может быть логически возможно обеспечить, но дополнительная сложность делает его маловероятным для решения в обозримом будущем MEF.

Надеюсь, это поможет;Я пометил этот вопрос как «призма», так как уверен, что другие члены сообщества Призма столкнулись с этим и могли бы дать совет.

5 голосов
/ 09 января 2012

Когда вы реализуете IDisposable, вы как бы говорите, что тип должен очищаться детерминированным способом (вызывая IDisposable.Dispose, а не случайным образом, когда сборщик мусора решает, что пришло время.

В вашем случае модели представлений будут удалены только тогда, когда вы утилизируете контейнер, что, вероятно, не то, что вы хотите сделать. Чтобы обойти это, я вижу два возможных решения:

  • Не применяйте IDisposable в моделях просмотра. Очевидно, вам все равно, когда они будут очищены, так зачем их делать IDisposable?

  • Вместо того, чтобы позволить контейнеру создавать каждую модель представления без общего доступа, вы можете использовать класс фабрики модели общего представления. Затем вы можете внедрить этот класс в владельцев моделей представлений, чтобы позволить владельцам точно создавать модели представлений. Предположительно эти владельцы также знали бы, когда располагать модели представлений.

По сути, если что-то одноразовое, это также должно быть разумной точкой в ​​вашем коде, где вам нужно избавиться от того, что является одноразовым.

4 голосов
/ 09 января 2012

Вы должны создать эти экземпляры через импортированную ExportFactory . Тогда у вас будет необходимый контроль, чтобы избавиться от них через ExportLifetimeContext<T>.Dispose().

Однако, это доступно только из коробки в следующей версии .NET (4.5) или в последних выпусках предварительного просмотра MEF на codeplex. (В более старых версиях MEF та же функциональность была реализована в качестве образца и называлась PartCreator , как описано в этом сообщении в блоге .)

2 голосов
/ 06 января 2014

Все остальные ответы предоставляют хорошие способы обойти эту проблему, но в итоге я в итоге использовал свой собственный пользовательский интерфейс ICleanup вместо IDisposable. Это, конечно, может не подходить для всех.

...