2

I have a foreach loop where I do some operations with images. I was getting an OutOfMemoryException when running this code with 50+ images; because the image instances are 15+ MB each.

var files = Directory.GetFiles(path).ToList();

foreach (var file in files)
{
    Image image = new Bitmap(file);

    //Do some operations
}

I removed the main logic because this problem still exists with this small piece of code. When I add GC.Collect(); in the foreach loop the problem is gone and I don't get an exception.

My question is: is the garbage collector too slow to clean up the images which aren't needed anymore without calling the Collect method or am I missing something else?

Never noticed this problem before. I never thought there would be a problem because the //Do some operations part needs ~1 second for each image. Should be enough time for the garbage collector I thought.

Mighty Badaboom
  • 6,067
  • 5
  • 34
  • 51
  • @YvetteColomb: as far as I can see it is a duplicate - OP is suffering Out Of Memory issues when using Bitmaps - that is because GC will not automatically handle the unmanaged memory. The solution given answers the question. See also answer by Romano below. – PaulF Jul 25 '17 at 11:21
  • @PaulF Ok, I missed something else...Should have thought about the use of `Bitmap`. Thank you! – Mighty Badaboom Jul 25 '17 at 11:22
  • @YvetteColomb: OP says the automatic cleaning up is slow to happen and out of memory issues occur - UNLESS Collect is manually called. OP does not say the call to Collect is the issue & has accepted the answer given. – PaulF Jul 25 '17 at 11:31
  • @YvetteColomb It really was a duplicate. Haven't thought about disposing the `Bitmap` and thought the GC was the problem. – Mighty Badaboom Jul 25 '17 at 11:33
  • @YvetteColomb: The original question the Mighty Bababoom came with was _"My question is: is the garbage collector too slow to clean up the images which aren't needed anymore without calling the Collect method or am I missing something else?"_ - in which case the answer was "Yes - you missed the fact that you need to Dispose bitmaps - otherwise GC will be very slow at collecting the images" - both parts of the answer addressed in the duplicate question. No change midstream. – PaulF Jul 25 '17 at 11:40
  • @YvetteColomb: I just did a quick search on something like "C# Bitmap GC slow memory leak" - lots of questions on here - I just thought that one was a best fit as it discussed memory errors when creating bitmaps in a loop & the problem going away when GC manually called & gave a reason for the apparent slowness in collection. This was at the top of the list & could have been a better choice : https://stackoverflow.com/questions/35366247/garbage-collector-too-slow-when-working-with-large-images - but the answers are not as well explained. – PaulF Jul 25 '17 at 11:56
  • this is a good read, go to no 8: https://www.toptal.com/c-sharp/top-10-mistakes-that-c-sharp-programmers-make – Adil H. Raza Nov 22 '18 at 11:42

3 Answers3

7

Perhaps you should work with using:

var files = Directory.GetFiles(path).ToList();

foreach (var file in files)
{
    using (Image image = new Bitmap(file))
    {
        // do work
    }
}

This way the Bitmap will be disposed after the iteration

Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
2

Have you tried explicitly disposing the instance?

var files = Directory.GetFiles(path).ToList();
foreach (var file in files)
{
    Image image = new Bitmap(file);

    //Do some operations
    image.Dispose();
    //image = null;
}

The same could be better implemented with using block.

Amit Joshi
  • 15,448
  • 21
  • 77
  • 141
1

The problem is not with GC but with your use of bitmaps. Although GC will eventually pick them up, you need to wrap image creation in using block to ensure their timely disposal:

foreach (var file in files)
{
    using (Image image = new Bitmap(file)) {
        //Do some operations
    }
}
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523