So, after discovering that the Bitmap class expects the original stream to stay open for the life of the image or bitmap, I decided to find out if the Bitmap class actually closes the stream when it is disposed.
Looking at the source code, the Bitmap and Image classes create a GPStream instance to wrap the stream, but do not store a reference to either the GPStream or the Stream instance.
num = SafeNativeMethods.Gdip.GdipLoadImageFromStreamICM(new GPStream(stream), out zero);
Now, the GPStream class (internal), does not implement a Release or Dispose method - nothing that would allow GDI to close or dispose of the stream. And since the Image/Bitmap class doesn't keep a reference to the GPStream instance, it seems that there is absolutely no way for either GDI, Drawing.Bitmap, or Drawing.Stream to close the stream properly.
I could subclass Bitmap to fix this, but, oh wait, it's sealed.
Please tell me I'm wrong, and that MS didn't just make it impossible to write code that doesn't leak resources with their API.
Keep in mind (a), Bitmap has no managed reference to the stream, meaning GC will collect it while it is still in use, and (b) .NET APIs take Bitmap/Image references and aren't deterministic about when they're done with them.
Since you supply the stream in this example, I'd imagine you are responsible for disposing it.
It is a good practice to have the method that opens a stream, close it as well. That way it is easier to keep track of leaks. It would be quite strange to have an other object closing the stream that you opened.
Because bitmap can't guarantee in which order the destructor is called it will not close the stream because it may already have been closed with its own destructor during garbage collection. Jeffrey Richter's CLR via C# has a chapter on memory management that explains with much more clarity than I can.
An easy workaround to the problem is:
var image = new Bitmap(stream);
image.Tag = stream;
Now the stream is referenced by the image and won't be garbage collected before the image is. If your stream happens to be a MemoryStream, it doesn't need to be disposed (its Dispose is a no-op). If not, you can dispose it when you dispose the image, or just let the GC do it when it gets around to it.
Related
I have an wrapper class that has a method that goes off and downloads a file from a web server and needs to return said file. The HttpWebResponse object returns a Stream for the body.
Should I return a stream? Or should I convert it to a byte array and return that instead?
This wrapper class may be used in several places so I need a solid way to return the file. In every case, the file will be saved somewhere after receiving it from the adapter class.
Short answer: Yes, it's fine.
Long answer: Yes, it's completely safe to return a Stream. The garbage collector is smart in .NET and you don't have to worry about the Stream being disposed of or anything. (That is, unless you call Dispose() on it — which you should not if you are planning on reusing it.)
Returning Stream object is totally valid. It would be responsibility of the code that calls the method returning stream to dispose it. Question is: does disposing response object in your wrapper method also dispose the stream? If so, then copy its content into a MemoryStream or make a temp file and return open stream to it instead.
I know this might seem silly, but why does the following code only work if I Close() the file? If I don't close the file, the entire stream is not written.
Steps:
Run this code on form load.
Close form using mouse once it is displayed.
Program terminates.
Shouldn't the file object be flushed or closed automatically when it goes out of scope? I'm new to C#, but I'm used to adding calls to Close() in C++ destructors.
// Notes: complete output is about 87KB. Without Close(), it's missing about 2KB at the end.
// Convert to png and then convert that into a base64 encoded string.
string b64img = ImageToBase64(img, ImageFormat.Png);
// Save the base64 image to a text file for more testing and external validation.
StreamWriter outfile = new StreamWriter("../../file.txt");
outfile.Write(b64img);
// If we don't close the file, windows will not write it all to disk. No idea why
// that would be.
outfile.Close();
C# doesn't have automatic deterministic cleanup. You have to be sure to call the cleanup function if you want to control when it runs. The using block is the most common way of doing this.
If you don't put in the cleanup call yourself, then cleanup will happen when the garbage collector decides the memory is needed for something else, which could be a very long time later.
using (StreamWriter outfile = new StreamWriter("../../file.txt")) {
outfile.Write(b64img);
} // everything is ok, the using block calls Dispose which closes the file
EDIT: As Harvey points out, while the cleanup will be attempted when the object gets collected, this isn't any guarantee of success. To avoid issues with circular references, the runtime makes no attempt to finalize objects in the "right" order, so the FileStream can actually already be dead by the time the StreamWriter finalizer runs and tries to flush buffered output.
If you deal in objects that need cleanup, do it explicitly, either with using (for locally-scoped usage) or by calling IDisposable.Dispose (for long-lived objects such as referents of class members).
Because Write() is buffered and the buffer is explicitly flushed by Close().
Streams are objects that "manage" or "handle" non-garbage collected resources. They (Streams) therefore implement the IDisposable interface that, when used with 'using' will make sure the non-garbage collected resources are clean up. try this:
using ( StreamWriter outfile = new StreamWriter("../../file.txt") )
{
outfile.Write(b64img);
}
Without the #Close, you can not be sure when the underlying file handle will be properly closed. Sometimes, this can be at app shutdown.
Because you are using a streamwriter and it doesn't flush the buffer until you Close() the writer. You can specify that you want the writer to flush everytime you call write by setting the AutoFlush property of the streamwriter to true.
Check out the docs. http://msdn.microsoft.com/en-us/library/system.io.streamwriter.aspx
If you want to write to a file without "closing", I would use:
System.IO.File
Operating system cache write to block devices to enable the OS to have better performance. You force a write by flushing the buffer after a write of setting the streamwriter to autoflush.
Because the C# designers were cloning Java and not C++ despite the name.
In my opinion they really missed the boat. C++ style destruction on scope exit would have been so much better.
It wouldn't even have to release the memory to be better, just automatically run the finalizer or the IDisposable method.
This seems like a fairly straightforward question, but I couldn't find this particular use-case after some searching around.
Suppose I have a simple method that, say, determines if a file is opened by some process. I can do this (not 100% correctly, but fairly well) with this:
public bool IsOpen(string fileName)
{
try
{
File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None);
}
catch
{
// if an exception is thrown, the file must be opened by some other process
return true;
}
}
(obviously this isn't the best or even correct way to determine this - File.Open throws a number of different exceptions, all with different meanings, but it works for this example)
Now the File.Open call returns a FileStream, and FileStream implements IDisposable. Normally we'd want to wrap the usage of any FileStream instantiations in a using block to make sure they're disposed of properly. But what happens in the case where we don't actually assign the return value to anything? Is it still necessary to dispose of the FileStream, like so:
try
{
using (File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None));
{ /* nop */ }
}
catch
{
return true;
}
Should I create a FileStream instance and dispose of that?
try
{
using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.None));
}
...
Or are these totally unnecessary? Can we simply call File.Open and not assign it to anything (first code example), and let the GC dispose of it right away?
Yes, you should definitely dispose of the FileStream. Otherwise the stream will remain open and the file won't be usable until a finalizer happens to clean it up.
The important thing here is ownership: for File.Open, the caller is assumed to "own" the stream returned to it - and if you own something which implements IDisposable, it's your responsibility to dispose of it.
Compare this with the situation of Image.FromStream: in that case, you pass in a stream and the Image then assumes that it owns that stream. You mustn't close the stream yourself, in that case - you have to dispose of the image when you're done, and it will dispose of the stream.
Calling a static method which returns something disposable almost always assumes that the caller takes ownership of the resource. Ditto constructors (which are effectively static methods.)
The irony in this case is that if you don't dispose of the stream returned by File.Open, you'll have found that the file is usable - at the same time as making it unusable until some indeterminate time.
If a method returns an IDisposable, I personally would always put it in a using block. Even if I don't assign the return value to anything.
Even if you don't assign it to a variable, the disposable object is still created. Dispose is not going to be called automatically. The only difference will be that the returned object will become immediately eligible for garbage collection, because there are no (strong) references to it.
The garbage collector does not call Dispose automatically when it reclaims an object. However, most IDisposable types provide a finalizer (which will be called just before the GC reclaims an object) that invokes Dispose as a fallback strategy (safety net) — study the IDisposable pattern to see how this is done:
~SomeClass // <-- the finalizer method will usually call Dispose;
{ // but you have no control over when it will be called!
Dispose(false);
}
Remember that you don't know when the garbage collector will run (because it's non-deterministic). Therefore, you also don't know when the finalizer method will be called. And because of that -- if you haven't called Dispose explicitly (either yourself, or with a using block) -- you don't know when it will be called by the finalizer.
That's the advantage of calling Dispose explicitly: You can free resources -- or at least allow the GC to free managed resources -- as soon as you're done with them, instead of holding on to resources until the finalizer gets called sometime in the future.
Yes, you don't want to leave the FileStream opened. For one, you won't even be able to open the file yourself after that. Calling Close() is good enough, but using using is probably the preferred pattern.
There's a much bigger problem with your code however. It cannot possibly work reliably on Windows. A typical scenario:
The File.Open() call succeeds. You close it
Your thread gets pre-empted by the Windows scheduler
Another thread in another process gets a chance to run, it opens the file
Your thread regains the CPU and continues after the File.Open() call
You open the file, trusting that it will work since IsOpen() returned false.
Kaboom.
Never write code like this, failure is extremely hard to diagnose. Only ever open a file when you are ready to start reading or writing to it. And don't close it until you are done.
Extra bonus: it is now obvious that you want to use a using statement.
When you call any method that returns something, an instance of that something is being created. Just because you're not actually capturing it, doesn't make it any less "there". Therefore, in the case of an IDisposable object, the object is being created by the method you're calling in spite of the fact that you're doing nothing with it. So yes, you still need to dispose of it somehow. The first approach with the using statement seems like it should work.
Is it necessary to manually manage the lifetime of System.Drawing objects?
Currently I am employing 'using' statements to minimise the lifespan of Brushes and other Drawing objects e.g.
using ( Brush br = new SolidBrush( color ) )
{
// Do something with br
}
Is this necessary or is it safe to let the garbage collector work its magic when and if it needs to?
As a quick aside to the question... what do people think is the cleanest way to achieve this?
When an object is IDisposable, then it is better to dispose it as soon as you do not need it any more. (It implements IDisposable for a reason).
Offcourse, when you forget to call Dispose, the Garbage collector will do its work at some time, and clean it up, so that resources are freed, but you can never tell or guess when the Garbage Collector will kick in, it is not deterministic.
So, my advice is: call Dispose manually (like you're doing now) as soon as you do not need the disposable object any more.
It is good to Dispose of System.Drawing object, however if you miss one or two when you get an exception etc, it is not the end of the world. (Other objects like opened files and database connections must always be disposed)
Having lots of “Using” statement all over your code make it more complex to understand. I would therefore in the case of System.Drawing object, consider just calling Dispose() on them at the end of the method.
In the past I have used a class I written “Dustcart”, that implements IDisposable, and contains a collection of objects to dispose. You can then write code like:
using(var dustcart = new Dustcard())
{
var p = dustcart.Add(new Pen(red, etc));
var b = dustcart.Add(new Brush(black));
Pen t;
if (someFlag)
{
t = p;
}
else
{
t = dustcard.Add(new Pen(etc));
}
}
The general rule of thumb is that if an object implements IDisposable you need to clean it up. IDisposable is not implemented on a whim in the .NET Framework - There are good reasons for it to be there.
As the others said: when you create an IDisposable object, you should Dispose it as soon as possible. In your specific example, if the color is known at compile time, you could use a standard brush such as Brush br = Brushes.Blue which you don't need to dispose.
If you are re-using the same colour over and over you could store the brush as a class-level member, however this would mean that the owning class should be IDisposable too, and dispose the brush member in it's dispose method.
This would increase the memory storage (by the size of one brush), but might reduce the amount of code (no using statements but an additional Dispose override).
I am using the 'using' statement just as you described in your question to guarantee that the Brush, Pen, Font, whatever resource is disposed of properly. In my code, I find the using statements cleaner than having explicit .Dispose() calls scattered throughout. But that's just my preference.
I agree with the answers above though: regardless of whether you prefer using statements or .Dispose calls, it's pretty important to clean up the resources manually, rather than relying on the garbage collector. (I was relying on the garbage collector at first and performance problems began to surface, even before things in the app were getting complicated.)
After calling System.Drawing.Icon.ToBitmap() to create an image, is it safe to dispose the original Icon?
The method converts an Icon to a new Bitmap object, so there will be no reference from the Bitmap to the Icon.
So yes, it is safe to dispose the Icon.
Yes. Icon.ToBitmap draws the Icon to a new Bitmap object so it is safe to dispose it afterwards.
Edit:
Looking at the Icon.ToBitmap() method in Reflector was interesting. I expected it to be a simple Graphics.DrawImage or Graphics.DrawIcon call but it is more involved than that. As long as it is possible the function will do a memory copy of the icon image data instead, but it will revert to a Graphics.DrawImage or Graphics.DrawIcon call if it cannot perform the copy. The memory copy is much faster so that is obviously the reason, but this makes the code much harder to read.
Yes.
If you don't need the icon any more, and have the bitmap stored somewhere, you're fine.