Уничтожить StreamResourceInfo.Stream - PullRequest
6 голосов
/ 26 мая 2011

Я использую StreamResourceInfo.Stream, чтобы получить BitmapImage с из ресурсов. Правильно ли Close и Dispose поток после его использования? Я спрашиваю, потому что в профайлере памяти, я получаю ошибку, если я делаю это. Профилировщик памяти говорит, что удаленный экземпляр не был GCed.

Если я посмотрю в Интернете, я смогу найти только эту запись в этой теме. В этом посте отвечающий говорит, что распоряжаться нечестно. Однако, если я смотрю на обстоятельства и на результат, я не думаю, что это правильно. Кто-нибудь знает, что такое правильное действие?
Дополнительная информация: в примерах msdn, которые я видел, они не удаляют и не закрывают.

Редактировать
Благодаря ответу Rick Sladkeys я нашел решение: Я присваиваю StreamResourceInfo.Stream StreamSource -объекту BitmapImage. В MSDN написано:

Установите для свойства CacheOption значение BitmapCacheOption.OnLoad, если вы хотите закрыть поток после создания BitmapImage. Параметр кэширования OnDemand по умолчанию сохраняет доступ к потоку до тех пор, пока не потребуется растровое изображение, а очистка выполняется сборщиком мусора.

Это означает, что BitmapImage становится владельцем потока. И именно поэтому профилировщик памяти выдает ошибку, если я закрываю / удаляю поток вручную: Bitmap будет содержать ссылку на поток (BitmapCacheOption OnDemand), и поэтому GC не будет выпускать его, пока BitmapImage допустим, но поток уже явно расположены. В этом конкретном примере утилизация - плохая идея.
Для полноты я также посмотрел в msdn пример вышеуказанной ссылки, где был вызван TextRange.Load. Для Load, наоборот, Load не берет на себя владение, и поэтому поток должен быть закрыт / утилизирован после окончания.

1 Ответ

10 голосов
/ 27 мая 2011

Путаница, и я согласен, что она сбивает с толку, происходит от тонкой, но критической концепции владения потока. В примерах MSDN вы можете посмотреть на них как «Смотри, нет Dispose, нет Close, так что я не должен этого делать?»

Но простой ответ заключается в том, что кто-то должен нести ответственность за закрытие потока. API, который вы, вероятно, вызываете:

  • Application.GetResourceStream

возвращает StreamResourceInfo, который является примитивным контейнером для потока и URL-адреса. Очевидно, что StreamResourceInfo не является владельцем потока. Поэтому, когда вы вызываете Application.GetResourceStream , вы теперь владеете потоком, который содержится в этом StreamResourceInfo, и, если вы больше ничего не сделали с ним, вы будете нести ответственность за его закрытие. API Application передал нам право собственности на поток, вернув его нам в качестве значения.

Теперь запутанная часть появляется, когда вы передаете поток другому объекту. Давайте возьмем пример MSDN:

// Navigate to xaml page
Uri uri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;

Теперь в этом примере нет Dispose и Close. Но там - это a передача права собственности потока от нас (вызывающей стороны) на экземпляр XamlReader. Поток больше не наша ответственность; мы передали право собственности кому-то другому. Фактически, XamlReader вызывает Close, когда это делается с потоком. Одна загадка раскрыта.

Причина, по которой это так проблематично, состоит в том, что концепция владения обычно подразумевается в документации, и мы должны "просто разобраться". Надеемся, что просто пересмотрев концепцию владения и тот факт, что она может быть передана, будет легче чувствовать себя не , звоня Close с безопасностью, которую новый владелец сделает . И даже если они этого не сделают, это больше не наша проблема!

...