-1

I am building an application that processes an incoming image from file or buffer and outputs results in the form of an array or doubles of fixed size. The application needs to be relatively quick. I ran into a problem with cycle time. I started recording cycle time while processing one image and it went from the minimum at 65ms and gradually started increasing to all the way 500ms which is way too slow. Sure enough, I checked on the memory usage and it was steadily increasing as well.

I'm running GC after every cycle and dumping unused variable as ofter as possible. I don't create new objects within the processing loop. Image processing is done on its own thread so that all the resources get dumped. It seems the majority of the cycle time increase happens when I'm pulling the image from file. What could I be missing?

here's the rough code, the full thing is pretty large. Main Function

         private void button4_Click(object sender, EventArgs e)
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        cogDisplay1.Image = null; 
        ImageFromFile.Operator.Open(Properties.Settings.Default.ImageFile, CogImageFileModeConstants.Read);
        ImageFromFile.Run();

        cogDisplay1.Image = ImageFromFile.OutputImage;
        cogDisplay1.AutoFit = true;
        Thread t = new Thread(Vision);
        t.Start();
        textBox3.Clear();
        sw.Stop();
        textBox3.AppendText(sw.ElapsedMilliseconds.ToString() + Environment.NewLine + "TS: " + t.ThreadState.ToString());
        textBox3.AppendText("GC" + GC.GetTotalMemory(true).ToString());
        GC.Collect(GC.MaxGeneration , GCCollectionMode.Forced, false);

    }

Image Processing

 public void Vision()
    {
        Stopwatch sw = new Stopwatch();
        sw.Start();

        try
        {

            AlignmentParams.ApproximateNumberToFind = 1;
            AlignmentParams.SearchRegionMode = 0;


            AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
            Fixture.InputImage = cogDisplay1.Image;
            Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
            Fixture.Run();
            AlignmentResult = null;


        #region FindLineTools 
        #endregion 
        #region FindEllipse 
        #endregion 


                sw.Stop();
                SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);




        }
        catch (Exception err) 
        {

           SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
           SetText(err.ToString() + Environment.NewLine);
           SetText("***************************" + Environment.NewLine);
        }




    }
msg256
  • 35
  • 6
  • 2
    You're missing the code in this post ;) – tnw Jun 25 '14 at 17:28
  • 3
    `GC.Collect` isn't a magic wand. It doesn't collect resources from the stack that still are referenced. It doesn't collect unmanaged memory. Finally, if you are keeping the processor pretty busy the GC may not clear as many resources before sleeping again. Code would be important to decide which (if any of these) would help – drew_w Jun 25 '14 at 17:32
  • 3
    You are missing the memory profiler diagnostics that tell you why your app is leaking. – Hans Passant Jun 25 '14 at 17:33
  • 2
    GC.Collect does absolutely nothing. it's pretty much equivalent to shouting "COLLECT" at the computer. If anything it can only hurt performance. – AK_ Jun 25 '14 at 17:35
  • I wish there was some kind of test before a developer was allowed to use GC.Collect :) – Stilgar Jun 25 '14 at 17:40
  • Please check if the classes implement IDisposable interface, if does, you have to call Dispose to release the memory in time. – Matt Jun 25 '14 at 17:41
  • 1
    _"done on its own thread so that all the resources get dumped"_ this is not guaranteed at all. You would need an AppDomain. And that you claim this makes me wonder about your actual resource handling. – H H Jun 25 '14 at 17:44
  • Please clean up your code before/during posting. Why do we have to endure all those empty lines and comment blocks? – H H Jun 25 '14 at 17:49
  • Maybe in your scenario switching GC to server mode can be helpful: – PrzemekG Jun 25 '14 at 21:42

2 Answers2

0

First, I would recommend to post a cleaned-up code for better readability (remove all commented-off stuff). Second, focus only on essential part, namely: your problem is memory overuse/leak due to heavy image processing (correct if wrong). Therefore, in your thread named Vision de-reference the image objects and set them to null immediately after processing completion (as mentioned above, GC is not a big help in your case). The concept briefly demonstrated by following code snippet:

    public void Vision()
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();

            try
            {

                AlignmentParams.ApproximateNumberToFind = 1;
                AlignmentParams.SearchRegionMode = 0;
                    AlignmentResult = AlignmentPat.Execute(cogDisplay1.Image as CogImage8Grey, null , AlignmentParams);
                Fixture.InputImage = cogDisplay1.Image;
                Fixture.RunParams.UnfixturedFromFixturedTransform = AlignmentResult[0].GetPose();
                Fixture.Run();
                AlignmentResult = null;

            // your coding stuff

                    sw.Stop();
                    SetText("V" + sw.ElapsedMilliseconds.ToString() + Environment.NewLine);

            }
            catch (Exception err) 
            {

               SetText(Environment.NewLine + "***********Error***********" + Environment.NewLine);
               SetText(err.ToString() + Environment.NewLine);
               SetText("***************************" + Environment.NewLine);
            }
finally{Fixture.InputImage=null}
Alexander Bell
  • 7,842
  • 3
  • 26
  • 42
0

Don't call GC.Collect. Let the VM decide when it is out of memory and must do the collection. You typically are not in a good position to decide the best time for a GC.Collect unless your running some other heartbeat or idle watching threads.

Secondly, ensure that whatever resources you're receiving from the method calls are being Disposed. Setting variables to NULL do NOT do this, you should be explicitly calling Dispose or within a Using block:

using(SomeResource resource = Class.GiveMeResource("image.png"))
{
   int width = resource.Width;
   int height = resource.Height;
   Console.Write("that image has {0} pixels", width*height);
} //implicitly calls IDisposable.Dispose() here.

You also need to do some memory and call profiling to detect where, if any, leaks exist.

enorl76
  • 2,562
  • 1
  • 25
  • 38