none
Garbage collection in C#

    Question

  • Is grabage collection slow in C# applications or that is completely normal? I tried to make a simple console app that changes video's format. I am not familiar with the whole conversion thing, so I'm just  writing every single frame of original file into a new file with a different format. The code is below:

    VideoFileWriter webmWriter = new VideoFileWriter();
                VideoFileReader input = new VideoFileReader();
                input.Open(args[0]);
                System.IO.File.Delete("output.webm");
                webmWriter.Open("output.webm", input.Width, input.Height, input.FrameRate, VideoCodec.Default, 192);
                   
                for (int i = 0; i < input.FrameCount; i++)
                {
                    Bitmap frame = new Bitmap(input.ReadVideoFrame());
                    Console.WriteLine("Writing frame " + i.ToString());
                    webmWriter.WriteVideoFrame(frame);
                    frame.Dispose();
                    GC.Collect();
                    GC.WaitForPendingFinalizers();
                }
                webmWriter.Close();
                input.Close();
    If I ditch the last two lines in the for loop - the ones related to garbage collector, the app quickly run out of memory. Is that normal?

    Tuesday, April 11, 2017 12:05 PM

Answers

  • You're right, guess I still have a lot to learn about the basics - I thought that the memory allocated by bitmap is beeing freed at the end of each iteration.

    In your case, it is (via the call to Dispose). And that's the problem.

    Allocating and freeing large chunks of memory is generally always going to be a time consuming process. This is nothing to do with C# or the garbage collector per se; you would get performance issues doing this in unmanaged C++ with alloc/free as well.

    Ideally, if you need a large chunk of memory you want to allocate it once, re-use it as often as you can, and then only dispose of it when you are entirely finished.

    I don't know much about the video reader/writer objects you are using, but it seems to me that input.ReadVideoFrame() is returning an image or bitmap anyway.

    So all you are achieving with...

    Bitmap frame = new Bitmap(input.ReadVideoFrame());

    ... is to create yet another bitmap from the one returned, only to write it out and dispose of it again.

    Do you need to even do that? Can you not use the image returned directly?

    E.g:

    Bitmap frame = input.ReadVideoFrame();
    
    webmWriter.WriteVideoFrame(frame);


    Tuesday, April 11, 2017 3:21 PM

All replies

  • Hello,

     From my experience, I have never ever had to induce Garbage Collection 

    Collect method.  When my projects require large amounts of RAM, I tend

    to keep it < 250MB per operations. This allows my app to remain speedy

    and responsive UI.

     Of course some apps, sound/video editing/conversions and data base may

    require more.  But, generally I would say let Garbage Collection do its work

    independently, not induced. Object scope is also a major factor. Good

    practices is call Dipsose, if object has one, before the method exits. But at

    the same time, be mindful of where the object was created in realtionship

    to the Dispose. 

     Your Code

    for (int i = 0; i < input.FrameCount; i++)
    {
        Bitmap frame = new Bitmap(input.ReadVideoFrame());
        Console.WriteLine("Writing frame " + i.ToString());
        webmWriter.WriteVideoFrame(frame);
        frame.Dispose();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }

     In the above snippet, you allocate and free RAM on every iteration. 

    I think this is a heavy burden on the Garbage Collection.  Perhaps

    you should allocate the Bitmap before the For Loop and Dispose after

    completion.  There is a big difference in your code and my suggestion.

     

     MSDN Ref:  https://msdn.microsoft.com/en-us/library/bb384155(v=vs.110).aspx

     Others may have different opinions. But its really about what you want the

    performance level of your App to have.

     Hope this helps :)

    Tuesday, April 11, 2017 12:50 PM
  • You're right, guess I still have a lot to learn about the basics - I thought that the memory allocated by bitmap is beeing freed at the end of each iteration.
    Tuesday, April 11, 2017 2:43 PM
  • You're right, guess I still have a lot to learn about the basics - I thought that the memory allocated by bitmap is beeing freed at the end of each iteration.

    In your case, it is (via the call to Dispose). And that's the problem.

    Allocating and freeing large chunks of memory is generally always going to be a time consuming process. This is nothing to do with C# or the garbage collector per se; you would get performance issues doing this in unmanaged C++ with alloc/free as well.

    Ideally, if you need a large chunk of memory you want to allocate it once, re-use it as often as you can, and then only dispose of it when you are entirely finished.

    I don't know much about the video reader/writer objects you are using, but it seems to me that input.ReadVideoFrame() is returning an image or bitmap anyway.

    So all you are achieving with...

    Bitmap frame = new Bitmap(input.ReadVideoFrame());

    ... is to create yet another bitmap from the one returned, only to write it out and dispose of it again.

    Do you need to even do that? Can you not use the image returned directly?

    E.g:

    Bitmap frame = input.ReadVideoFrame();
    
    webmWriter.WriteVideoFrame(frame);


    Tuesday, April 11, 2017 3:21 PM
  • Hello,

     From my experience, I have never ever had to induce Garbage Collection 

    Collect method. 

    GC.Collect call is discouraged because it decreases the current performance of the application. Whenever you call the garbage collector to performs a collection , it suspends all currently executing threads. This can become a performance issue if you call GC.Collect more often than is necessary. You should be careful not to place code that calls GC.Collect at a point in your program where users could call it frequently. However, if you can reliably test your code to confirm that calling Collect() won't have a negative impact then go ahead.
    Wednesday, April 17, 2019 5:16 AM