1
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;

namespace TrainSVM
{
    class Program
    {
        static void Main(string[] args)
        {
            FileStream fs = new FileStream("dg.train",FileMode.OpenOrCreate,FileAccess.Write);
            StreamWriter sw = new StreamWriter(fs);
            String[] filePathArr = Directory.GetFiles("E:\\images\\");

            foreach (string filePath in filePathArr)
            {
                if (filePath.Contains("HBP"))
                {
                    sw.Write("1 ");
                    Console.Write("1 ");
                }
                else
                {
                    sw.Write("1 ");
                    Console.Write("1 ");
                }

                using (Bitmap originalBMP = new Bitmap(filePath))
                {


                    /***********************/
                    Bitmap imageBody;
                    ImageBody.ImageBody im = new ImageBody.ImageBody(originalBMP);
                    using (imageBody = im.GetImageBody(-1))
                    {

                        /* white coat */
                        Bitmap whiteCoatBitmap = Rgb2Hsi.Rgb2Hsi.GetHuePlane(imageBody);
                        float WhiteCoatPixelPercentage = Rgb2Hsi.Rgb2Hsi.GetWhiteCoatPixelPercentage(whiteCoatBitmap);
                        //Console.Write("whiteDone\t");
                        sw.Write("1:" + WhiteCoatPixelPercentage + " ");
                        Console.Write("1:" + WhiteCoatPixelPercentage + " ");

                        /******************/
                        Quaternion.Quaternion qtr = new Quaternion.Quaternion(-15);
                        Bitmap yellowCoatBMP = qtr.processImage(imageBody);
                        //yellowCoatBMP.Save("yellowCoat.bmp");
                        float yellowCoatPixelPercentage = qtr.GetYellowCoatPixelPercentage(yellowCoatBMP);
                        //Console.Write("yellowCoatDone\t");
                        sw.Write("2:" + yellowCoatPixelPercentage + " ");
                        Console.Write("2:" + yellowCoatPixelPercentage + " ");

                        /**********************/
                        Bitmap balckPatchBitmap = BlackPatchDetection.BlackPatchDetector.MarkBlackPatches(imageBody);
                        float BlackPatchPixelPercentage = BlackPatchDetection.BlackPatchDetector.BlackPatchPercentage;
                        //Console.Write("balckPatchDone\n");
                        sw.Write("3:" + BlackPatchPixelPercentage + "\n");
                        Console.Write("3:" + BlackPatchPixelPercentage + "\n");
                    }
                }


                sw.Flush();

            }


            sw.Dispose();
            fs.Dispose();

        }

    }
}

8 Answers8

10

There are some Bitmap instances there that you aren't disposing. You should really try to get in the habit of using a using block rather than disposing manually, to stop these things slipping through the net.

David M
  • 71,481
  • 13
  • 158
  • 186
  • 1
    Indeed, using-blocks add a try-finally for you as well (as you certainly know) which his code lacks. – Skurmedel Apr 01 '10 at 11:02
  • 1
    Why a try-finally? If all the disposables are in using blocks these guarantee the Dispose call without needine one. – David M Apr 01 '10 at 11:09
  • I think you misunderstood me, that's one of the things you get from the using-statement. I didn't mean that you need try-finally with using-blocks, I mean that you won't need try-finally with using-blocks. :) – Skurmedel Apr 01 '10 at 11:14
  • Sorry, I misread "add" for "and" (or maybe this was your edit?). – David M Apr 01 '10 at 11:15
  • It might've been, nevermind we were in agreement all along :) – Skurmedel Apr 01 '10 at 11:17
5

If you're getting the exception on this line:

using (Bitmap originalBMP = new Bitmap(filePath))

then that may mean you're trying to load an invalid or corrupted image file. For reasons known to no man, the OutOfMemoryException is what's thrown in this case. It actually has nothing to do with really being out of memory.

Try googling "bitmap.fromfile outofmemoryexception".

MusiGenesis
  • 74,184
  • 40
  • 190
  • 334
  • 1
    That's a good one. Completely misleading exceptions are my favorite. – Mike Two Apr 01 '10 at 11:40
  • @Mike: it's extra-bad in this case, because image files tend to be some of the largest objects you deal with in .Net, so when you run into an `OutOfMemoryException`, it's easy to assume that you're really, you know, *out of memory*. – MusiGenesis Apr 01 '10 at 11:49
2

Shouldn't you be disposing imageBody as well?

I see it's opened:

Bitmap imageBody; 
ImageBody.ImageBody im = new ImageBody.ImageBody(originalBMP); 
imageBody = im.GetImageBody(-1); 

But I don't see you disposing of it / setting it to null?

AndrewC
  • 6,680
  • 13
  • 43
  • 71
  • +1. Certainly he should, huge images lying undisposed can never be good. – Skurmedel Apr 01 '10 at 10:59
  • Disposing it and setting it to null are two completely different things (although I suspect you probably know that already). – LukeH Apr 01 '10 at 11:00
  • I added it. and again running my code. I'm still getting this error. – imageWorker Apr 01 '10 at 11:02
  • What did you add? Can you update your original post to reflect your changes? – AndrewC Apr 01 '10 at 11:03
  • btw.. I'm declaring these variables in side the `foreach` loop block. So doesn't that mean in each loop iteration. The previous object reference is destroyed and object should be collected by GC? – imageWorker Apr 01 '10 at 11:09
  • Yes and no, imageWorker: GC will collect them, but it won't necessarily happen straight away. – Dan Puzey Apr 01 '10 at 11:27
  • 2
    Also: why are people suggesting he dispose of this ImageBody class with no idea of what it actually does? If the image is passed in, there's no obvious reason that the class should even be disposable. – Dan Puzey Apr 01 '10 at 11:45
  • @Dan because it was the next logical step to take? – AndrewC Apr 01 '10 at 13:33
2

Maybe you are bitten by this bug: https://connect.microsoft.com/VisualStudio/feedback/details/521147/large-object-heap-fragmentation-causes-outofmemoryexception

In this case, adding

    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
    GC.WaitForPendingFinalizers();
    GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);

in the loop might help.

Or use sos.dll http://www.codeproject.com/KB/dotnet/Memory_Leak_Detection.aspx to see, where you leak memory.

Henrik
  • 23,186
  • 6
  • 42
  • 92
2

You have a lot of calls to various classes, ImageBody,Rgb2Hsi,BlackPatchDetection etc

I assume these are you own code. Any of these could be holding on the resources.

I would suggest you grab a profiler and run some tests.

Most of them have trial versions giving you a couple of days with it.

Best .NET memory and performance profiler?

Community
  • 1
  • 1
Mesh
  • 6,262
  • 5
  • 34
  • 53
1

Try to take the Bitmap originalBMP = new Bitmap(filePath); in a using()

using (Bitmap originalBMP = new Bitmap(filePath)) {
  // your code....   
  sw.Flush();   
}

All within the using() clause is definitly disposed after leaving the clause. You could also set you variables to null, after they are disposed.

chriszero
  • 1,311
  • 3
  • 13
  • 26
1

You should use the using statement instead of Dispose() whereever possible. This way, you see in the declaration immediately that this instance you just create is freed.

Which is better?

Bitmap bmp = new Bitmap(filePath);
// .. pages of code goes here ..
bmp.Dispose(); // hopefully not forgotten

or

using (Bitmap bmp = new Bitmap(filePath))
{
// .. pages of code goes here ..
}

The using statement also ensures that all instances are freed even if you leave the current block/method prematurely with return,break or even an exception.

Note that you can put multiple assignments into the head of the using statement!

codymanix
  • 28,510
  • 21
  • 92
  • 151
  • you have still lots of images in your code which are not disposed. Additionally, did you have a look at ImageBody? Does this class derive from IDisposable? If so you should also dispose it. – codymanix Apr 01 '10 at 15:22
  • You should also use .net memoryprofiler to see which objects consume so much memory – codymanix Apr 01 '10 at 15:23
0

As with any Garbage collection issue, my approach would be to start commenting things out and seeing if I can still reproduce memory leaks. Things to try out:

  1. Instantiate only one instance of Bitmap in the loop to see if the memory usage changes.
  2. Dispose/not Dispose that one instance of Bitmap to see if disposing makes any difference.

From what I can see in the latest version of the code, whiteCoatBitmap, yellowCoatBitmap and blackPatchBitmap are not being disposed. Surround those with a using block as well.

Igor Zevaka
  • 74,528
  • 26
  • 112
  • 128