none
WinForms controls memory issue? RRS feed

  • Question

  • I am experiencing a strange "memory leak" when I am using a pushbutton to start my program.  Here is a snippet:

    using Kitware.VTK

    namespace vtkclasspractice
    {
        public partial class Form3 : Form
        {
            public Form3()
            {
                InitializeComponent();
            }

            private void button_test_Click(object sender, EventArgs e)
            {

                   "Body of my code"

            }

         }

    }

    My problem is that the memory in "Body of my code" never clears until I get out of the scope of button_test_Click.  There is a loop in "Body of my code" that is supposed to re-process ~5MB of image data, but instead it seems as though the memory just adds-up each iteration. 

    I know this is a problem of the pushbutton, because when I place "Body of my code" right after InitializeComponent(), within the same scope, memory does not grow.  It seems as though garbage collection does not work inside of the button_test_Click method.

    Any suggestions?

    Thursday, November 17, 2016 8:10 AM

All replies

  • Are you properly disposing of the objects that you are using to process the image, i.e. calling Dispose() or by using "using"?
    Thursday, November 17, 2016 8:36 AM
  • I think so.  I only encounter this problem when I run "Body of my code" by having it run under button_click control.  When I have this code run under the initialization of the GUI, I do not encounter any memory issues.  In fact any code that I write under the button_click control, the memory does not clear until the code runs out of the button_click control.  

    When I do run "Body of my Code" under the button_click control, the memory increases until I get "Out of Memory" error.  It's as though button_click control holds some reference to my code so that the garbage collection is not active.  I notice that dispose() then GC.collect() does nothing either while I'm looping inside of the code.

    Very mysterious...  Maybe this is my unique issue...

    Friday, November 18, 2016 6:54 PM
  • Question 1:
    How are you measuring the memory use? Taskmanager, Private Bytes, asking the GC? It is easy to measure the wrong thing.
    How much memory does my .NET application use? Explaining the Task Manager figure versus Private Bytes in performance monitor.

    Question 2:
    Could you be mistaking "not yet garbage collected" with "memory leak"? The two have nothing to do with one another. The GC will not collect unless it has to collect. Wich means memory useage will just keep increasing.
    Garbage Collection - Pros and Limits

    Question 3:
    What is your code actually doing?
    We can hardly help you debug code if you do not show us the actuall code. What you gave use should not even compile. In particular, where are you storing any references/values you create inside that function? Function scope variables?


    Remember to mark helpfull answers as helpfull and close threads by marking answers.

    Saturday, November 19, 2016 1:30 AM
  • Christopher84,  thank you so much for the reply and your willingness to help out.  Means so much to me.  To address your questions,

    Question 1: I am simply looking at the Taskmanager to measure the memory.  What I observe is that the memory keeps on increasing until I get "Out of Memory" error message when I run my code.  That leads me to conclude that my code has some memory issue.

    Question 2: I think you are right in pointing-out that it is "not yet garbage collected" issue.  Because as I have pointed-out that I see memory being collected intermittenly when I run "The Body of my Code" in the same scope as the initialization of my winform ( InitializeComponent();).  Only when I try to run "The Body of my Code" with the button click do I see memory issues.

    Question3: "The body of my code" calculates statistical information (ave, standard deviation, max, min, etc...) given a 3D grid of floating numbers.  I'll share the code at the end, but I'm using a 3rd party software (VTK). 

    As a stand-alone code, of course my code will not compile, but I'm using the automatically-generated winform classes, which includes Program.cs and Form3.Designer.cs that initializes my winform.   Now that I am forced to look and understand those classes, I see a line that is very suspicous...:

    this.button_test.Click += new System.EventHandler(this.button_test_Click);

    I'm now thinking that this line of automatically generated code when I add the button_click button might not be referencing and de-referencing the button click event correctly, and hence disabling the garbage collector to work properly when button click event happens.  Can you help me?  

    Here is the whole code snippet for the "Body of my Code":

    private void button_test_Click(object sender, EventArgs e)
            {
                //get dose image, white image, and black imgage from XML
                double origin_x = -33.846523;
                double origin_y = -32.30963;
                double origin_z = -14.65001;

                double spacing_x = .2539;
                double spacing_y = .2539;
                double spacing_z = .25;

                int extent_x1 = 0;
                int extent_x2 = 255;
                int extent_y1 = 0;
                int extent_y2 = 255;
                int extent_z1 = 0;
                int extent_z2 = 151;

                string dosefile = "../../../dose.img";

                //mask this dose image
                vtkImageReader2 dose = vtkImageReader2.New();  //faster than vtkImageReader
                dose.SetDataScalarTypeToFloat(); //dose image
                dose.SetFileDimensionality(3);
                dose.SetDataOrigin(origin_x, origin_y, origin_z);
                dose.SetDataSpacing(spacing_x, spacing_y, spacing_z);
                dose.SetDataExtent(extent_x1, extent_x2, extent_y1, extent_y2, extent_z1, extent_z2);
                dose.SetNumberOfScalarComponents(1);
                dose.SetDataByteOrderToBigEndian();
                dose.SetFileName(dosefile);
                dose.Update();
                vtkImageData dose3D = dose.GetOutput();

                //initialize 2D white images
                vtkImageData whiteimage = vtkImageData.New();
                whiteimage.SetSpacing(.2539, .2539, .25);
                whiteimage.SetOrigin(-33.846523, -32.30963, -14.65001);
                //whiteimage.SetOrigin(-33.846523, -32.30963, 0);
                whiteimage.SetExtent(0, 255, 0, 255, 0, 0);  //Coordinate=extent*spacing
                whiteimage.SetScalarTypeToUnsignedChar();
                whiteimage.AllocateScalars();
                whiteimage.SetNumberOfScalarComponents(1);
                int count = whiteimage.GetNumberOfPoints();
                for (int i = 0; i < count; ++i)
                {
                    whiteimage.GetPointData().GetScalars().SetTuple1(i, 1);
                }

                //initialize 3D black image by appending white images to the extent and setting input as 0
                vtkImageAppend append_whiteimage = vtkImageAppend.New();
                append_whiteimage.SetAppendAxis(2);
                for (int i = 0; i < extent_z2 + 1; i++)
                {
                    append_whiteimage.AddInput(whiteimage);
                    append_whiteimage.Update();
                }
                vtkImageMathematics black_image = vtkImageMathematics.New();
                black_image.SetConstantK(0);
                black_image.SetOperationToMultiplyByK();
                black_image.SetInputConnection(append_whiteimage.GetOutputPort());

                vtkImageData Image3D = black_image.GetOutput();
                Image3D.Update();

                //DVH_calculator DVH = new DVH_calculator(whiteimage, Image3D, dose3D, "../../../PTV.xml");
                String[] files = { "../../../ring.xml", "../../../body.xml", "../../../ring.xml", "../../../ring.xml", "../../../PTV.xml", "../../../Couch.xml", "../../../total_lung.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../PTV.xml", "../../../total_lung.xml" };

                foreach (string element in files)
                {
                    new DVH_calculator(whiteimage, Image3D, dose3D, element);
                }

            }


    • Edited by suhseungsoo Tuesday, November 22, 2016 12:52 AM
    Tuesday, November 22, 2016 12:51 AM
  • Okay, if you got a OOM then there is a actualyl memory problem. Either you are using more memory then supported, to many large pieces or a bona-fide memory leak.

    Memory leaks with events usually mean you are using a variable that was not created in teh Event function itself. Usually something like a global list. Let's put this code into syntax highlighting and see if we see anything:

    private void button_test_Click(object sender, EventArgs e)
            {
                //get dose image, white image, and black imgage from XML
                double origin_x = -33.846523;
                double origin_y = -32.30963;
                double origin_z = -14.65001;
    
                double spacing_x = .2539;
                double spacing_y = .2539;
                double spacing_z = .25;
    
                int extent_x1 = 0;
                int extent_x2 = 255;
                int extent_y1 = 0;
                int extent_y2 = 255;
                int extent_z1 = 0;
                int extent_z2 = 151;
    
                string dosefile = "../../../dose.img";
    
                //mask this dose image
                vtkImageReader2 dose = vtkImageReader2.New();  //faster than vtkImageReader
                dose.SetDataScalarTypeToFloat(); //dose image
                dose.SetFileDimensionality(3);
                dose.SetDataOrigin(origin_x, origin_y, origin_z);
                dose.SetDataSpacing(spacing_x, spacing_y, spacing_z);
                dose.SetDataExtent(extent_x1, extent_x2, extent_y1, extent_y2, extent_z1, extent_z2);
                dose.SetNumberOfScalarComponents(1);
                dose.SetDataByteOrderToBigEndian();
                dose.SetFileName(dosefile);
                dose.Update();
                vtkImageData dose3D = dose.GetOutput();
    
                //initialize 2D white images
                vtkImageData whiteimage = vtkImageData.New();
                whiteimage.SetSpacing(.2539, .2539, .25);
                whiteimage.SetOrigin(-33.846523, -32.30963, -14.65001);
                //whiteimage.SetOrigin(-33.846523, -32.30963, 0);
                whiteimage.SetExtent(0, 255, 0, 255, 0, 0);  //Coordinate=extent*spacing
                whiteimage.SetScalarTypeToUnsignedChar();
                whiteimage.AllocateScalars();
                whiteimage.SetNumberOfScalarComponents(1);
                int count = whiteimage.GetNumberOfPoints();
                for (int i = 0; i < count; ++i)
                {
                    whiteimage.GetPointData().GetScalars().SetTuple1(i, 1);
                }
    
                //initialize 3D black image by appending white images to the extent and setting input as 0
                vtkImageAppend append_whiteimage = vtkImageAppend.New();
                append_whiteimage.SetAppendAxis(2);
                for (int i = 0; i < extent_z2 + 1; i++)
                {
                    append_whiteimage.AddInput(whiteimage);
                    append_whiteimage.Update();
                }
                vtkImageMathematics black_image = vtkImageMathematics.New();
                black_image.SetConstantK(0);
                black_image.SetOperationToMultiplyByK();
                black_image.SetInputConnection(append_whiteimage.GetOutputPort());
    
                vtkImageData Image3D = black_image.GetOutput();
                Image3D.Update();
    
                //DVH_calculator DVH = new DVH_calculator(whiteimage, Image3D, dose3D, "../../../PTV.xml");
                String[] files = { "../../../ring.xml", "../../../body.xml", "../../../ring.xml", "../../../ring.xml", "../../../PTV.xml", "../../../Couch.xml", "../../../total_lung.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../ring.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../body.xml", "../../../PTV.xml", "../../../total_lung.xml" };
    
                foreach (string element in files)
                {
                    new DVH_calculator(whiteimage, Image3D, dose3D, element);
                }
    
            } 


    Remember to mark helpfull answers as helpfull and close threads by marking answers.

    Tuesday, November 22, 2016 3:00 PM