0

Hello and Thanks for any answers!

I am not a .NET person although, I can code OK or understand an existing C# code, since I am a C/C++ person. Sorry for the bit long text, but didn't have a choice.

I wrote a simple .NET application as follows. That's the full code below. The form is very small with just one button. See the simple btn code below. First time I click on the btn, the Windows File selection dialog shows, I hit cancel on that dialog. I see memory go up by 6 MB (from 15MB to 21 MB). I did this for about 10 times. From the second an subsequent times, the memory kept increasing by small amounts (few hundred Ks) and total went up to 23 MB or so. The memory used never decreased. I left the app for an hour thinking memory will come back. It didn't. With the GC collector code below, the first time memory increase is same, but subsequently, it it didn't increase memory, it would go and down but not below 21 MB.

Even when I removed all the code inside the button click and kept clicking the button memory would slowly go up by 0.1 MB in the Windows Task Manager, every few clicks. Never comes back. But when I just put the GC collect code alone in the Btn click code (nothing else), the memory doesn't increase in the task manager.

My question is, why is the 6 MB is permanently lost even though the Windows file dialog is closed? Windows Task manager for this app shows the same memory increase effect (although the memory shown is different size for valid reasons compared to the one shown thru the app). OR will .NET release memory some other day, or it will only do something if it realizes application process memory is in dangerously high.

Reason to ask this question is, we have a .NET UI App running in a machine that is used by several users to kick of jobs 2 shifts a day for months without exiting the app since we cannot exit the app (for reasons). The App will create a .NET worker class/function does the work/job, exit the worker, and be ready for next job. Every time users kick of something, the memory keeps on increasing causing issues after a month or so depending the frequency of usage. I am not .NET person. I thought its not that easy leak memory in .NET :-) That's why wrote a simple .NET/C# test. I see that memory is getting lost easily :-)

Any help with sample test app? or its just how .NET works and there is nothing apart from adding the GC collector code everywhere in the app to mitigate the memory usage increase?

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    private void Form1_Load(object sender, EventArgs e)
    {
    }
    private void button1_Click(object sender, EventArgs e)
    {
        Process currentProcbefore = Process.GetCurrentProcess();
        long memoryUsedbefore = currentProcbefore.PrivateMemorySize64;

        var filePath = string.Empty;

        //FolderBrowserDialog test = new FolderBrowserDialog();
        //if (test.ShowDialog() == DialogResult.OK)
        //{
        //    //Get the path of specified file
        //    filePath = test.SelectedPath;
        //}

        using (FolderBrowserDialog test = new FolderBrowserDialog())
        {
            if (test.ShowDialog() == DialogResult.OK)
            {
                //Get the path of specified file
                filePath = test.SelectedPath;
            }
        }

        //GC.Collect();
        //GC.WaitForPendingFinalizers();
        //GC.Collect();

        Process currentProcafter = Process.GetCurrentProcess();
        long memoryUsedafter = currentProcafter.PrivateMemorySize64;

        MessageBox.Show("Mem Usage before:" + memoryUsedbefore + "  After:" + memoryUsedafter);
    }
}

Thanks Jacob

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
user702426
  • 149
  • 1
  • 2
  • 6
  • Process will not release the private bytes as soon as they are not needed (even the memory was freed by the `GC`), so this is not an ideal tool to prove that memory leak is happening. – Guru Stron Mar 18 '23 at 00:03
  • _"I thought its not that easy leak memory in .NET "_ - it depends, there are ways to achieve it quite easy, especially when working with unmanaged resources and/or UI apps. I have not tried but I doubt that added snippet actually shows that there is a memory leak. As for your actual app - one of the "easy" ways to leak memory in UI apps is forgetting to unsubscribe from events. Since you claim that GC.Collect helps I would check what GC mode are you running - UI apps usually should run in workstation mode but based on your description sound like you are running in server one for some reason. – Guru Stron Mar 18 '23 at 00:10
  • See [workstation and server garbage collection](https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/workstation-server-gc) and [runtime configuration options for garbage collection](https://learn.microsoft.com/en-us/dotnet/core/runtime-config/garbage-collector). Server mode is gready, if it sees that there is enough memory usually it will not collect, workstation should be on other hand frequent and quick one. – Guru Stron Mar 18 '23 at 00:12
  • "Reason to ask this question" that whole paragraph is irrelevant. .NET has many reasons to hold on to memory in the small "test" you did, none of which are leaks, eg why release if there is no pressure? And JIT compilation takes up memory permanently, along with many other static initializations that are not released. Your other application may have a memory leak, but this question has nothing to do with it – Charlieface Mar 19 '23 at 01:26
  • Does this answer your question? [.NET Core app Process Memory doesn't decrease after objets are deallocated](https://stackoverflow.com/questions/58129758/net-core-app-process-memory-doesnt-decrease-after-objets-are-deallocated) – Charlieface Mar 19 '23 at 01:28

2 Answers2

0

To quote Microsoft:

Conditions for a garbage collection

Garbage collection occurs when one of the following conditions is true:

  • The system has low physical memory. The memory size is detected by either the low memory notification from the operating system or low memory as indicated by the host.
  • The memory that's used by allocated objects on the managed heap surpasses an acceptable threshold. This threshold is continuously adjusted as the process runs.
  • The GC.Collect method is called. In almost all cases, you don't have to call this method because the garbage collector runs continuously. This method is primarily used for unique situations and testing.

GC is only run when .NET runtime decides it needs to be run.

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
pm100
  • 48,078
  • 23
  • 82
  • 145
0

Memory will be automatically released by OS when other programs actually need it.

Other languages that manage memory manually also do not show immediate memory usage reduction when released directly.

Segel
  • 22
  • 1
  • 5
  • Thank you everyone for the responses. Very much appreciated! I will read the links provided by you all for more information and try to code better. I gather, the flat answer for the simple test application is, the button code is not wrong and that's how .NET works with respect to memory management. Fair enough. – user702426 Mar 19 '23 at 18:18