Утилизировать StreamResourceInfo.Stream

#wpf #performance #idisposable #imagesource #memory-profiling

#wpf #Производительность #idisposable #источник изображения #профилирование памяти

Вопрос:

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

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

Редактировать
Благодаря ответу Рика Сладкейса я нашел решение: я присваиваю StreamResourceInfo.Stream StreamSource -свойству BitmapImage . В msdn написано:

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

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

Комментарии:

1. Dispose при внутренних вызовах streams Close . (Или на самом деле обычно наоборот)

2. @Albin: Да, я в курсе этого. AFAIK здесь Close вызывает Dispose . Но вопрос не в этом. Вопрос в том, желательно ли вообще закрывать / утилизировать конкретный поток. В msdn-examples они этого не делают, и если я посмотрю на результат, я сомневаюсь, что это предшествовало / ожидалось. Но в любом случае спасибо.

Ответ №1:

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

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

  • Application.GetResourceStream

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

Теперь возникает запутанная часть, когда вы передаете поток другому объекту. Давайте рассмотрим пример 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 . Но происходит передача права собственности на поток от нас (вызывающей стороны) к XamlReader экземпляру. Поток больше не является нашей ответственностью; мы передали право собственности кому-то другому. На самом деле, XamlReader вызывает Close , когда это делается с потоком. Одна загадка решена.

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