How to free the memory after the BitmapImage is no longer needed?

23,407

Solution 1

I believe the solution you are looking for is at http://www.ridgesolutions.ie/index.php/2012/02/03/net-wpf-bitmapimage-file-locking/. In my case, I was trying to find a way to delete the file after it was created, but it appears to be a solution to both issues.

Doesn't free up memory:

var bitmap = new BitmapImage(new Uri(imageFilePath));

Frees up memory, and allows file to be deleted:

var bitmap = new BitmapImage(); 
var stream = File.OpenRead(imageFilePath);

bitmap.BeginInit();
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.StreamSource = stream;
bitmap.EndInit();
stream.Close();
stream.Dispose();

Optionally, also freeze the BitmapImage:

bitmap.Freeze();

Solution 2

In my situation it seems that the bitmap caching was the issue. I was previously loading bitmaps like this:

Bitmap bitmap = new Bitmap();

using(var stream = new FileStream(...))
{
    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.OnLoad;
    bitmap.StreamSource = stream;
    bitmap.EndInit();
}

bitmap.Freeze();
image.Source = bitmap;

Continuously replacing image.Source the same way just built up memory, manually forcing garbage collection wasn't really helping.

Instead, disabling the caching and having it use the stream (requires leaving the stream open until the image is displayed) paired with manual garbage collection eliminated memory build up for me.

Stream mediaStream;

void DisposeMediaStream()
{
    if (mediaStream != null)
    {
        mediaStream.Close();
        mediaStream.Dispose();
        mediaStream = null;
        GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
    }
}

void Update()
{
    DisposeMediaStream();

    var bitmap = new BitmapImage();
    mediaStream = new FileStream(...);

    bitmap.BeginInit();
    bitmap.CacheOption = BitmapCacheOption.None;
    bitmap.StreamSource = mediaStream;
    bitmap.EndInit();

    bitmap.Freeze();
    ControlImage.Source = bitmap;
}

This way I can cycle through tons of images (like Windows Photo Viewer) and memory stays low. Note that the stream does not have to stay open once the image has actually rendered.

Share:
23,407

Related videos on Youtube

AgentFire
Author by

AgentFire

Updated on July 09, 2022

Comments

  • AgentFire
    AgentFire almost 2 years

    First, I load a BitmapImage into the Image control, whice is located on the Window. Then I work with the Image control and then close the Window.

    I do it 2-3 times in a minute and my memory fills up very quickly because the images do not unload from the memory for some reason when the window is closed.

    So how do I unload BitmapImage from Image.Source control manually to free the RAM?

  • AgentFire
    AgentFire over 12 years
    GC.Collect() does not free the resources even when i null the reference to the BitmapImage.
  • AgentFire
    AgentFire over 12 years
    I've tried to use new BitmapImage(new Uri(link), new RequestCachePolicy(RequestCacheLevel.NoCacheNoStore)); but there is no difference. Memory is still in use.
  • abhinav
    abhinav over 12 years
    How does your reference chain look? Is it something like Image->BitmapImage->MemoryStream->filestream->Actual bytes in memory then you'll have to null-reference the correct object, else you'll still be using memory.
  • AgentFire
    AgentFire over 12 years
    It looks like this: Image.Source = new BitmapImage(new Uri(link));
  • AgentFire
    AgentFire over 12 years
    Seems to be I need to use Image.BeginInit and .EndInit.
  • KMC
    KMC about 6 years
    I tried the above code, but had to set BitmapCacheOption to OnLoad or else I cannot run Update() to add multiple images in a loop
  • zhaorufei
    zhaorufei about 6 years
    Works for me, change bitmap.CacheOption further reduce the commited memory. BTW, stream.Close and stream.Dispose are duplicated.
  • majestzim
    majestzim over 5 years
    Please note: I recall originally attempting to put the stream in a using statement, but memory continued to build up very quickly. Using stream.close and stream.dispose worked much better.
  • Clemens
    Clemens over 3 years
    When you set a BitmapImage's StreamSource, always also set BitmapCacheOption.OnLoad and close the stream right after EndInit, like using (var fs = new FileStream(...)) { ... bitmap.CacheOption = BitmapCacheOption.OnLoad; bitmap.StreamSource = fs; bitmap.EndInit(); }