Large Amounts of Byte[] Kept in Memory by StreamAsIStream Instances - c#

I have been memory-profiling a C# .NET WPF application, and I have found that there is a large number of Byte[] instances staying in memory. They are predominantly kept alive by instances of StreamAsIStream handles, which reference System.IO.MemoryStream instances, which finally reference the System.Byte[] instances.
These System.Byte[] instances amount to over 5mb of memory, so I'd like to understand why they're sitting in memory and if there's anything I can do to get rid of them (unless they're necessary, of course).
I've tried to do some research on my own, but I have been unable to find much. The only thing I've seen pertains to the use of ElementHost when hosting WinForms elements in a WPF application, but ElementHost is not used throughout the program.
I was able to put breakpoints in the constructor of SystemAsIStream and found that these objects are instantiated when I create new instances of BitmapImage using streams, but they appear to persist even after the BitmapImage instances have been GC'd.
I have also used WinDBG to try to examine the SystemAsIStream instances, but I am not very experienced with using that program. The most I could gather was that the instances are strong handles, but I basically knew that already.
Does anybody have any idea why this might be happening and what I can do about it? Even more information about StreamAsIStream would be appreciated.
Further information: I'm using .NET 4.0 and my target platform is x86.
Edit: the BitmapImage instances are created with the following code:
public static BitmapImage BitmapImageFrom(Stream stream)
{
BitmapImage image = new BitmapImage();
image.BeginInit();
image.CreateOptions = BitmapCreateOptions.None;
image.StreamSource = stream;
image.EndInit();
return image;
}
The stream is from the following:
stream = Application.GetResourceStream(new Uri(string.Format(#"pack://application:,,,/Images/{0}/{1}", folder, imageName))).Stream;
I've tried creating the BitmapImages by setting their CacheOption field to BitmapCacheOption.OnLoad and disposing of the stream, but that doesn't seem to make a difference (could be wrong -- I may have done it wrong or something).

Related

Is it possible to create Avalonia.Media.Imaging.Bitmap from System.Drawing.Bitmap?

I am writing an application in Avalonia and using OpenCvSharp to get frames from the camera. This worked with WPF - there I just called
Image.Source = Mat.ToBitmapSource();
but this doesn't work in Avalonia, because there is a different type of Image control, and a different type of its Source property.
I tried doing this via a MemoryStream, but then the Bitmap constructor crashes with an ArgumentNullException (although the stream is not null).
Of course, as soon as I asked you that, I found a solution. Load the image into memory and then call it back.
I was getting the same type of error but that was fixed after I implemented the using statement.
//Place this in your class to create a class variable and create the System.Drawing.Bitmap Bitmap
private System.Drawing.Bitmap irBitmap = new System.Drawing.Bitmap(256, 192, PixelFormat.Format24bppRgb);
//Add this using statement to the function you're converting inside of
//to convert the System.Drawing.Bitmap to Avalonia compatible image for view/viewmodel
using (MemoryStream memory = new MemoryStream())
{
irBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
//AvIrBitmap is our new Avalonia compatible image. You can pass this to your view
Avalonia.Media.Imaging.Bitmap AvIrBitmap = new Avalonia.Media.Imaging.Bitmap(memory);
}
Let me know if you have questions or how to specifically tie this into your app. There wasn't a lot of code provided earlier so I didn't have any idea what to name variables for your specific use case.

WritableBitmap memory usage

I've been writing an assembly to handle some basic image manipulation and have hit a stumbling block that I am a bit stuck on resolving.
The crux of the issue is when I create a new System.Windows.Media.Imaging.WriteableBitmap, the resultant private bytes for the process jumps to an unbelievable amount.
My test console app has the following code and a couple of breakpoints to see when the memory usage spikes.
using (Stream imageStreamSource = new FileStream(#"c:\temp\input\snow.jpg", FileMode.Open, FileAccess.Read, FileShare.Read))
{
BitmapImage bmpi = new BitmapImage();
bmpi.BeginInit();
bmpi.CreateOptions = BitmapCreateOptions.None;
bmpi.StreamSource = imageStreamSource;
bmpi.EndInit();
var bmp = new WriteableBitmap(bmpi);
}
At the end of the .EndInit() call, the memory usage is only a few hundred bytes, but once the WriteableBitmap is instantiated, the memory jumps to several hundred MB.
Memory Usage shown in Visual Studio
The image I'm trying to process isn't the world's largest (4134x2924) and is less than 300KB in size. A quick calculation of what it would take in memory to represent 32bpp comes to about 40MB. Unless I'm missing something obvious, something looks wrong.
Image I'm working on as a test (snow.jpg)
I've read about possible memory leaks in WritableBitmap in older versions of Silverlight, but I'm using .net 4.0 and I've yet to see reports of a leak in this version.
Does anyone have any insight or solutions to this as it does not scale to what will be a web process eating that much memory in production?

Loading an image from a stream without keeping the stream open

Is it possible to use the FromStream method of System.Drawing.Image without having to keep the stream open for the lifetime of the image?
I have an application which loads a bunch of toolbar graphics from resource files, using a combination of Image.FromStream and Assembly.GetManifestResourceStream.
The problem I'm having is while this works fine on Windows 7, on Windows XP the application crashes if a user interface element linked to one of these images is disabled. On Windows 7, the image is rendered in grayscale. On XP, it crashes with an out of memory exception.
After a load of hairpulling I have finally traced it to the initial loading of the image. As a matter of course, if I create any object implementing IDisposable that is also destroyed in the same method, I wrap it in a using statement, for example
using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName))
{
image = Image.FromStream(resourceStream);
}
If I remove the using statement so that the stream isn't disposed, then the application no longer crashes on XP. But I now have a bunch of "orphan" streams hanging about - the images are stored in command classes and these correctly dispose of the images when they themselves are disposed, but the original stream isn't.
I checked the documentation for FromStream and it confirms the stream needs to remain open. Why this hasn't crashed and burned on the Windows 7 development system is a mystery however!
I really don't want this stream hanging around, and I certainly don't want to have to store a reference to this stream as well as the image so I can dispose of it later. I only have need of that stream once so I want to get rid of it :)
Is it possible to create the image and then kill of the stream there and then?
The reason the stream needs to be open is the following:
GDI+, and therefore the System.Drawing namespace, may defer the decoding of raw image bits until the bits are required by the image. Additionally, even after the image has been decoded, GDI+ may determine that it is more efficient to discard the memory for a large Bitmap and to re-decode later. Therefore, GDI+ must have access to the source bits for the image for the life of the Bitmap or the Image object.
The documented workaround is to create either a non-indexed image using Graphics.DrawImage or to create an indexed Bitmap from the original image as described here:
Bitmap and Image constructor dependencies
According to the documentation of Image.FromStream, the stream must be kept open while the image is in use. Therefore, even if closing worked (and there's nothing to say you can't close a stream before it's disposed, as far as the stream object itself goes) it may not be a very reliable approach.
You could copy the image to another image object, and use that. However, this is likely to be more memory intensive than just keeping the stream open.
You could save the stream to a temporary file and use the Image.FromFile method. Or simply don't embed the image, keep it as a file and load it from this file at runtime.
I'am sure this will help someone :)
I used it for my dataGridView_SelectionChanged:
private void dataGridViewAnzeige_SelectionChanged(object sender, EventArgs e)
{
var imageAsByteArray = File.ReadAllBytes(path);
pictureBox1.Image = byteArrayToImage(imageAsByteArray);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}

Running out of memory when getting a bitmap from a server?

I'm making an application which uses MANY images. The application gets the images from a server, and downloads them one at a time.
After many images the creation of a bitmap returns an exception, but i don't know how to solve this. Here is my function for downloading the images:
public static Bitmap getImageFromWholeURL(String sURL)
{
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(sURL);
myRequest.Method = "GET";
// If it does not exist anything on the url, then return null
try
{
HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(myResponse.GetResponseStream());
myResponse.Close();
return bmp;
}
catch (Exception e)
{
return null;
}
}
Can anyone help me out here?
Thanks in advance!
Stream that response to disk rather than keep it in memory. Then keep around the information about the image you've saved to a temporary place instead of the image itself.
If you're showing these all in a Picturebox (and based on your comments I think you are) then you should Dispose of the old images (this blog entry helps explain it):
if(myPictureBox.Image != null)
{
myPictureBox.Image.Dispose();
}
myPictureBox.Image = getImageFromWholeURL(url);
As a side note on style, method names are supposed to be PascalCase, not camelCase and I'd lose the hungarian notion on the parameter.
"Many images" is of course closely associated with running out of memory. Bitmaps can get large, they'll eat up a lot of unmanaged virtual memory. You'll have to make your program smarter and store less bitmaps in memory. Or save them temporarily to a file. Or re-download them if necessary. And properly clean up their resources with the Dispose() method, especially important for the Bitmap class.
What do you do with the System.Drawing.Bitmap objects? Do you keep all of them in memory? Then it is inevitable that you'll get an out of memory exception at some point.
Based on your needs you should discard the images at some point. If you do need them, store them in a file in flash. Also, try using files of smaller sizes.

When drawing an image: System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI

I've got a global Graphics object created from a Panel. At regular intervals an image is picked up from the disk and drawn into the panel using Graphics.DrawImage(). It works fine for a few iterations and then I'm getting the following helpful exception:
System.Runtime.InteropServices.ExternalException: A generic error occurred in GDI+.
at System.Drawing.Graphics.CheckErrorStatus(Int32 status)
at System.Drawing.Graphics.DrawImage(Image image, Int32 x, Int32 y)
at System.Drawing.Graphics.DrawImage(Image image, Point point)
I ruled out memory leaks as I dispose of the image object when I'm done with it. I know that the images are not corrupted and can be read fine as the program executes fine for a while before the panel stops showing.
I ran into the same problem when using a PictureBox but this time at least I got an error instead of nothing.
I checked the GDI objects and USER objects in the Task Manager but they're always around 65 user objects and 165 GDI objects when the app works and when it doesn't.
I do need to get to the bottom of this as soon as and it's not like I can stick breakpoints in .NET System libraries and see where exactly execution fails.
Thanks in advance.
EDIT: This is the display code:
private void DrawImage(Image image)
{
Point leftCorner = new Point((this.Bounds.Width / 2) - (image.Width / 2), (this.Bounds.Height / 2) - (image.Height / 2));
_graphics.DrawImage(image, leftCorner);
}
the image load code:
private void LoadImage(string filename, ref Image image)
{
MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword);
image = Image.FromStream(memoryStream);
memoryStream.Close();
memoryStream.Dispose();
memoryStream = null;
}
_image is global and its reference is updated in LoadImage. They are passed as parameters as I want to change the global references from as few places as possible only and keep the other methods self contained. _graphics is also global.
I've also got a webBrowser control for web sites and I either show an image or a website at one time. when there's time to display an image, the following code executes:
webBrowser.Visible = false;
panel.Visible = true;
DrawImage(_image)
_image.Dispose();
_image = null;
_image is referencing a pre-loaded image.
Hope this helps.
Your problem is similar to what I thought, but not quite. When you are loading the image, you are loading it from a MemoryStream. You have to keep the stream open for the lifetime of the image, see MSDN Image.FromStream.
You must keep the stream open for the lifetime of the Image.
The solution is to make a copy of your image in the FromImage function:
private void LoadImage(string filename, ref Image image)
{
using (MemoryStream memoryStream = DecryptImageBinary(Settings.Default.ImagePath + filename, _cryptPassword))
{
using (tmpImage = Image.FromStream(memoryStream))
{
image = new Bitmap(tmpImage);
}
}
}
Similar to the dispose problem I mentioned, the image will seem to work and then randomly fail when the underlying stream is garbage collected.
Without a little more code there is not enough to properly diagnose here, however, one thing to look at is that you may have disposed on the image your a drawing with at some point earlier and it is only after the garbage collector runs that your code is failing. Are you using cloned images anywhere? One thing I was suprised to learn is that if you do a straight clone of an image, you are not cloning the underlying bitmap that the image rely's upon, only the image structure, to create a proper copy of an image you have to create a new image:
var newImage = new Bitmap(img)
as
var newImage = oldImg.Clone();
oldImg.Dispose();
...
gr.DrawImage(newImage, new Rectangle(0,0,newImage.Width,newImage.Height);
will work for a while, but then fail at some random point...

Categories