Dispose StreamResourceInfo.Stream

2019-04-28 07:55发布

I use StreamResourceInfo.Stream to get BitmapImages from resources. Is it correct to Close and Dispose the stream after using it? I ask because in memory profiler, I get an error if I do so. Memory profiler says that a disposed instance has not been GCed.

If I look on the web, I only can find this post to this topic. In this post, the responding person says, that it is meaninfull to dispose. However if I look at the circumstances and on the effect, I don't think that this is right. Does someone know what is the right action?
Additional information: In the msdn examples I have seen, they don't Dispose or Close.

Edit
Thanks to Rick Sladkeys answer, I found the solution: I assign StreamResourceInfo.Stream to the StreamSource-property of the BitmapImage. In msdn is written:

Set the CacheOption property to BitmapCacheOption.OnLoad if you wish to close the stream after the BitmapImage is created. The default OnDemand cache option retains access to the stream until the bitmap is needed, and cleanup is handled by the garbage collector.

This means, BitmapImage takes the ownership of the stream. And that's why memory profiler shows an error if I Close/Dispose the stream manually: Bitmap will hold a reference to the stream (BitmapCacheOption OnDemand) and therefore GC will not release it as long as the BitmapImage is valid, but the stream is already explicitely disposed. In this specific example, disposing is a bad idead.
For completness, I have also looked in msdn for the example of the above link where TextRange.Load was called. For Load, it is the opposite, Load does not take the ownership and therefore the stream must be closed/disposed after finishing.

1条回答
做自己的国王
2楼-- · 2019-04-28 08:25

The confusion, and I agree it is confusing, comes from the subtle but critical concept of ownership of the stream. In the MSDN examples you can look at them as say "Look, no Dispose, no Close, so I'm not supposed to do that?"

But the simple answer is that somebody has to be responsible for closing the stream. The API you are probably calling:

  • Application.GetResourceStream

returns a StreamResourceInfo that is a primitive container for a stream and an URL. Clearly the StreamResourceInfo does not own the stream. So when you call Application.GetResourceStream you now own the stream that is contained in that StreamResourceInfo and, if you did nothing else with it, you would be responsible for closing it. The Application API transfered ownership of the stream from itself to us by returning it as a value to us.

Now the confusing part comes in when you pass the stream to another entity. Let's take an MSDN example:

// 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;

Now in this example there is no Dispose and no Close. But there is a transfer of ownership of the stream from us (the caller) to the XamlReader instance. The stream is no longer our responsibility; we have passed ownership over to someone else. In fact, XamlReader does call Close when it is done with the stream. One mystery solved.

The reason this is so problematic is that the concept of ownership is usually implicit in the documentation and we are supposed to "just figure it out." Hopefully just revisiting th concept of ownership and the fact that it is transferable will make it easier to feel comfortable not calling Close with the security that the new owner will. And even if they don't, it's not our problem anymore!

查看更多
登录 后发表回答