I use StreamResourceInfo.Stream
to get BitmapImage
s 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.
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!