3

I created a simple example to test the image control's memory handling. On a dockpanel there are two buttons ("Load" and "Reset") and an image control. In the code behind, the event handlers of the buttons look like this:

private void LoadButton_Click(object sender, RoutedEventArgs e)
{
  var dlg = new OpenFileDialog
              {
                Title = "Open image file",
                DefaultExt = ".tif",
                Filter = "",
                Multiselect = false,
                InitialDirectory = "D:\\testimages"
              };


  dlg.ShowDialog();

  string file = dlg.FileName;

  if (!string.IsNullOrEmpty(file))
  {      

    if (this.img.Source != null)
    {
      this.img.Source = null;
      this.img.UpdateLayout();

      GC.Collect();
    }

    var bi = new BitmapImage();
    bi.BeginInit();
    bi.CacheOption = BitmapCacheOption.OnLoad;
    bi.UriSource = new Uri(file);
    bi.EndInit();
    bi.Freeze();


    this.img.Source = bi;
  }
  else
  {
    this.img.Source = null;
    this.img.UpdateLayout();

    GC.Collect();
  }
}

private void ResetButton_Click(object sender, RoutedEventArgs e)
{
   this.img.Source = null;
   this.img.UpdateLayout();

   GC.Collect();

}

When I load the first image, the memory usage increases. Hitting the Reset-button, the memory is released correctly. So far this looks like correct behaviour. But if I do not "reset", but load another image, the memory usage increases. "Reset" does only release the memory of the latest image. How can I make sure, that the memory of previously loaded images gets released when loading the next image?

The images I use are app. 4000 x 1000 px with a resolution of 300dpi.

tabina
  • 1,095
  • 1
  • 14
  • 37
  • did you try calling GC.Collect() in LoadButton_Click as well? – thumbmunkeys Jan 21 '14 at 09:46
  • I modified the example a little bit: when using a local variable for 'bi' the memory gets released completely, when the "Reset" button is clicked. But the GC.Collect() call in the "Load" does not make any difference. When loading several images one after the other the memory of the previously loaded image does not get released until I hit "Reset". – tabina Jan 21 '14 at 10:03
  • I want to use the above code in a custom image control using binding to set the current image. I need to have the memory released, when the image control receives an empty file or null. – tabina Jan 21 '14 at 10:07
  • so your current code doesnt work ? you could test if your code works with a [1sec wait](http://stackoverflow.com/questions/10458118/c-sharp-waiting-one-second-in-running-program) in it so your GC get some more Time to Collect – WiiMaxx Jan 21 '14 at 10:33
  • 1
    Did you ever fix this? I'm having the same problem. Loading 18 BitmapImages puts me at 1GB of memory. Is there a good way to only load the image in memory when it is displayed? – AndrewRalon Jul 24 '15 at 17:06
  • I am still not completely satisfied, but when I use GC.Collect(); and GC.WaitForPendingFinalizers(); between the display of two images, it is almost ok. – tabina Jul 28 '15 at 09:54
  • @andrewralon: you may want to try some control that supports virtualizing if you want to display a list of images but only load those into memory that are actually displayed. – tabina Jul 28 '15 at 09:55
  • @tabina Thanks for the nudge in the right direction. Would you recommend a virtualizing control for me to research? – AndrewRalon Jul 28 '15 at 12:27
  • 1
    @andrewralon: That depends on what you want. A control for a simple virtualized list is already available in WPF. That would be the VirtualizingStackPanel, listing items in one direction only. If you need more functionality, like e.g. a VirtualizingWrapPanel, lots of examples for an individual implementation can be found online. – tabina Jul 28 '15 at 15:04
  • maybe `BitmapCacheOption.None` will help? – Mikolaytis Dec 18 '17 at 15:43

0 Answers0