Releasing BitmapImages used as Image control Source (memory problem) - wpf

I have a simple WPF window with an Image control and a Slider control under it. When the user moves the slider, I'm loading and setting various images as Source of the Image-control. I got quite a few images, varying in size up to a 200 KB, but when I move that slider back and fourth, the program starts to eat quite a lot of memory. Hundreds and hundreds of megs of memory. Most of it gets garbage collected eventyally, but not all.
Maybe WPF isn't the way to go or should I force a G/C? I've tried loading the image as Bitmap and getting the bitmap source with Imaging.CreateBitmapSourceFromHBitmap() and Win32-api's to delete and dispose and so on, but I'm just making things worse :)
I guess I should try to grab the existing image source and release it somehow before loading and assigning a new one.
Any ideas?
EDIT
I'm adding some sample code that worked fine and seems to keep the memory low and fine:
private Image _lastImage;
// Event when user moves the slider control, load image using the filname in
// the _images[] array which contains hundreds of images
private void SliderChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
if (_lastImage != null)
_lastImage.Dispose();
var image = Image.FromFile(_images[(int)ImageSlider.Value]);
Snapshot.Source = ImageToBitmapImage(image);
_lastImage = image;
}
private static ImageSource ImageToBitmapImage(Image image)
{
BitmapImage bitmapImage;
using (var ms = new MemoryStream())
{
image.Save(ms, ImageFormat.Jpeg);
bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(ms.ToArray());
bitmapImage.EndInit();
}
return bitmapImage;
}

Forcing a GC collection is indeed horrible. Instead call the .Dispose() method of the Bitmap object, that's what it's there for!

The method you are using (Imaging.CreateBitmapSourceFromHBitmap()) is unmanaged and probably requires that you manually .Dispose() of it.
WPF allows you to load a bitmap via a given URI : see http://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapimage.aspx
The GC will take care of collecting any managed objects you have (by using BitmapImage for example).
You are probably loading too many images to memory. the source images accumulate memory pretty fast (1024x786 image at 32bit color takes up around 3mb of ram). The GC has to work very hard to clean them up. You could reduce the size of the image after loading (scale it down) and use up less memory
Finally, the GC does not guarantee that all memory will be released after the GC cycle.
It promises "best effort". although typically calling GC.Collect(0); will force a full GC cycle and release almost everything that can be released.

Related

Clearing previously loaded images in WinForm from resources

Purpose of my WinForm application is to load and display for a short while randomly selected picture from specific folder. I'm doing this using a PictureBox like so (this line gets adjusted by random number generator to generate different number file name):
pictureBox1.Image = Image.FromFile(#"C:\pics\1.png");
After a while it loads different image file, but looking at the Diagnostic View, I see that the Process Memory is rising by approx. 1MB with every image loaded. After about 100 pictures, the size rises by 100MB, even though the pictures were replaced. One of the timers that controls display duration includes some methods I found here to try and flush the image from resources:
private void displayDuration(object sender, EventArgs e)
{
pictureBox1.Visible = false;
pictureBox1.Image = null;
pictureBox1.Invalidate();
timer2.Enabled = false;
}
but to no avail. Memory keeps increasing, but the Tick function works since setting visibility to false works just fine.
How do I properly flush this image from memory once I don't need it anymore?
I'm trying not to include ImageList, but if you think it could resolve this memory issue, I could add it in.
Mr. Reza Aghaei was correct, Dispose() does the trick, I just used it wrong:
pictureBox1.Dispose();
which just ruined the pictureBox. Disposing the image in pictureBox is the correct way:
pictureBox1.Image.Dispose();
I shouldn't have given up on that method so early. Thank you very much.

Data binding performance issues

I am writing a map control that can display a bench of geometries. For better performance, I draw all my geometries using DrawingVisuals which I then write into a RenderTargetBitmap as shown in the code below:
public class Map{
public ImageSource MapDrawingImage{get;set;}
private void RenderMap(){
MapDrawingImage= new RenderTargetBitmap(w, h, 96, 96, PixelFormats.Pbgra32);
foreach (Layer layer in map.Layers) {
System.Windows.Media.DrawingVisual layerDrawing = Render(layer, map);
MapDrawingImage.Render(layerDrawing);
}
}
}
In order to display the map, the main window has an Image control which Source is set to Map.MapDrawingImage image source. To automatically update the image, I use the following data binding:
RenderOptions.SetBitmapScalingMode(mapImage, BitmapScalingMode.LowQuality);
// Map image binding
Binding mapBinding = new Binding();
mapBinding.Source = map;
mapBinding.Path = new PropertyPath("MapDrawingImage");
mapImage.SetBinding(System.Windows.Controls.Image.SourceProperty, mapBinding);
This works very well when the map is static. However, in a dynamic mode where the map is updated at a rate of 5 to 10 times a second, the data binding seems to fall a bit short behind and the application slows down. I have searched for long days and I found out that:
RenderTargetBitmap does not use hardware acceleration thus causing some delays when rendering the map.
Data binding might also cause some delays refreshing the map image
Is there any better way to improve the map performance (RenderTargetBitmap replacement, data binding improvement) ?
Thanks in advance,
Databinding is updated in a seperate thread. So this will always be with a delay. Also it works with a queue, so when the databinding can't keep up the queue will grow bigger and bigger. The solution would be that you use an image which is static and change the image itself instead of replacing it with another image.

Using resources images in WPF

From what I've seen, WPF images' source is a BitmapSource object while the Resources images are read as bitmap. I've easily found a way to convert images from Bitmap format into BitmapSource format but I believe that running this conversion every time I need an image is just costly in terms of performance and memory consumption (The Bitmaps themselves are static but I guess that the conversion allocates a new object in memory for the BitmapSource).
I thought about holding an in-memory, lazy cache for the BitmapSource objects, that way I will only need to run the conversion once per image. However, I find it hard to believe that this is the proper solution for this issue.
The nature of the application is that the data extends over time and the business objects are never disposed. Therefore, this assumption will only hold in case the implementation will hold static resources for these static images.
I will very much appreciate the proper solution for this issue.
I'm not sure I understand what you mean but you can use Image from Resources like this.
If you have an Image resource named "B1.png" and you set "Build Action" to "Resource" for it than you can use it in xaml like this.
<Image Name="c_image" Source="/YourAssemblyName;component/Resources/B1.png" />
and in code behind like this
Image img = new Image();
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri("pack://application:,,,/YourAssemblyName;component/Resources/B1.png");
bitmapImage.EndInit();
img.Source = bitmapImage;

WPF WriteableBitmap Memory Leak?

I'm trying to figure out how to release a WriteableBitmap memory.
In the next section of code I fill the backbuffer of a WriteableBitmap with a really large amount of data from "BigImage" (3600 * 4800 px, just for testing)
If I comment the lines where bitmap and image are equaled to null, the memory it´s not release and the application consumes ~230 MB, even
when Image and bitmap are no longer used!
As you can see at the end of the code its necessary to call GC.Collect() to release the memory.
So the question is, what is the right way to free the memory used by a WriteableBitmap object? Is GC.Collect() the only way?
Any help would be great.
PS. Sorry for my bad english.
private void buttonTest_Click(object sender, RoutedEventArgs e)
{
Image image = new Image();
image.Source = new BitmapImage(new Uri("BigImage"));
WriteableBitmap bitmap = new WriteableBitmap(
(BitmapSource)image.Source);
bitmap.Lock();
// Bitmap processing
bitmap.Unlock();
image = null;
bitmap = null;
GC.Collect();
}
Are you running your test on Windows XP, using .Net 3.5 SP1?
If so, then it is a known problem, that will be fixed in 4.0.
See
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/5d88cdf1-e992-4ad4-8f56-b5dbf92dcf1c
In general, memory should eventually be freed automatically as needed.
However, for that to happen, you need to be sure that the object is truly unused: No references to the object may exist anywhere, including references which "aren't used anymore". So, in particular, if you place your WriteableBitmap and original BitmapSource in variables of a long-lived class, they won't be released until the container is.
Also, WPF uses a retained GFX model: when you render, you're actually just storing instructions on how to render. The "instructions" on how to render a bitmap include a reference to the bitmap - so if you ever render a large bitmap, then for a while (at least as long as it's on screen - even if the version on screen is tiny) those images will be retained.
In practice; store references to these bitmaps only where they are needed, and if the context in which they live is long-lived (a long method call, or a method call generating a closure with a reference to the bitmaps, or a member of a long-lived class) then set them to null once they're no longer needed.
It is not necessary to manually free the memory; GC.Collect() should be superfluous. As a rule of thumb, only use GC.Collect during benchmarking to get an indication of memory consumption and/or to start with a clean slate. Overall performance is generally decreased by calls do GC.Collect().
Forcing a GC without setting image and bitmap to null won't clean them up because they are still being referenced locally and are thus considered root references. This is nothing specifically to do with the WriteableBitmap and more a question of how GC works.
If you don't set them to null and don't force a garbage collection then they will be collected once the method exists and a GC occurs. That is recommended above forcing the collection yourself because you're probably hurting performance rather than helping it.

Resizing images in Silverlight 3 using WriteableBitmap

This is my first day with Silverlight. I’m trying to prototype an application which (among other functions) should be able to resize user supplied images. It should be able to handle and display several resized images at once. The most obviously approaches I've tried seem to "leak" memory in the sense that the original bitmaps are still being referenced in some way which causes Silverlight to allocate hundreds of megabytes of memory after a while. I just want to be able to load the images one by one, resize them and keep the small versions.
To be precise, I've tried the following:
Creating a list of System.Windows.Controls.Image's (and scaling them). I'm not surprised that this has not worked.
Creating a list of rectangles filled by image brushes. I'm not surprised either.
Rendering the bitmaps into System.Windows.Media.Imaging.WriteableBitmap. I expected this to perform well; I assumed that the bitmaps are really just drawn directly and not referenced in any way. However, the memory consumption indicated otherwise.
Here is a snippet of the relevant piece of code:
// create image source
Stream stream = file.OpenRead();
BitmapImage bmpImg = new BitmapImage();
bmpImg.SetSource(stream);
stream.Close();
// create temporary image from it
Image tmpImg = new Image();
tmpImg.Source = bmpImg;
// this is required by WriteableBitmap
tmpImg.Measure(new Size(100, 100));
tmpImg.Arrange(new Rect(0, 0, 100, 100));
// prepare scaling to 100x100
ScaleTransform scaleTrans = new ScaleTransform();
double scale = (double)100 / (double)Math.Max(bmpImg.PixelHeight, bmpImg.PixelWidth);
scaleTrans.CenterX = 0;
scaleTrans.CenterY = 0;
scaleTrans.ScaleX = scale;
scaleTrans.ScaleY = scale;
// render
WriteableBitmap writeableBitmap = new WriteableBitmap(100, 100);
writeableBitmap.Render(tmpImg, scaleTrans);
writeableBitmap.Invalidate();
// final image
Image img = new Image();
img.Source = writeableBitmap;
I hope I'm not missing anything silly, but it looks to OK to me and does the right thing (except the memory problem). Please also bear in mind that code quality is not supposed to be a production quality; it’s just a quick and dirty prototype.
I noticed that I’m not alone; I found questions related to image manipulation in Silverlight. I’m also aware of the fact that I could use some third party library, do processing on the server or write something even myself, but I’m surprised that Silverlight does not offer any basic image manipulation functions. It does not seem to be an uncommon requirement given where Silverlight positions itself.
Have you looked at the WriteableBitmapEx project? It's an open source project with a tonne of extension methods for the WriteableBitmap class. Here's how you resize:
BitmapImage image = new BitmapImage();
image.SetSource(dialog.File.OpenRead());
WriteableBitmap bitmap = new WriteableBitmap(image);
WriteableBitmap resizedBitmap = bitmap.Resize(500, 500, WriteableBitmapExtensions.Interpolation.Bilinear);
// For uploading
byte[] data = resizedBitmap.ToByteArray();
I don't know about the specifics here, but if you're leaking resources - you might look at which of your objects implements the IDisposable interface. I would guess that the Stream and Image classes implement this interface. And if they do - calling Dispose() on them (or wrapping their usage in a "Using" statement) will cause them to free their resources immediately rather than waiting for the garbage collector to kick in eventually.

Resources