RAM - memory leak in the application

Hi,

I am using windows forms, Win 7, VS 2010.

I am working on the application that has some memory leak - memory consumption grow, even if I don't do anything with the app, and I don't know why?

Is it possible to see what objects are in the RAM?

Greetings, Frenky
AntonioRodrigoAsked:
Who is Participating?
 
AntonioRodrigoConnect With a Mentor Author Commented:
This code has solved the problem. Memory usage drops from 70Mb to 4Mb or even less.

    public class MemoryOptimizer
    {
        // Methods
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern IntPtr GetProcessHeap();
        [DllImport("kernel32.dll")]
        internal static extern uint HeapCompact(IntPtr heap, uint flags);
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll")]
        internal static extern bool HeapLock(IntPtr heap);
        public static void HeapOptimizer()
        {
            GC.Collect(GC.MaxGeneration);
            GC.WaitForPendingFinalizers();

            long l = 1;
            //SetProcessWorkingSetSize(Process.GetCurrentProcess().Handle, UIntPtr.Zero,UIntPtr.Zero);
            EmptyWorkingSet(Process.GetCurrentProcess().Handle);
            IntPtr processHeap = GetProcessHeap();
            if (HeapLock(processHeap))
            {
                try
                {
                    HeapCompact(processHeap, 0);
                }
                catch (Exception ex)
               
                { throw ex;
               
                }
                finally
                {
                    HeapUnlock(processHeap);
                }
            }
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll")]
        internal static extern bool HeapUnlock(IntPtr heap);
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll")]
        internal static extern bool SetProcessWorkingSetSize(IntPtr process, UIntPtr minimumWorkingSetSize, UIntPtr maximumWorkingSetSize);
        [DllImport("Psapi.dll")]
        internal static extern bool EmptyWorkingSet(IntPtr process);
    }
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
You shouldn't have 'memory leaks' in .NET - because objects are garbage collected.

Because objects are garbage collected means that memory usage may increase during the lifetime of the app !!  That is because the GC mechanism will only release memory when it determines it is necessary, not when an object is no longer in use.

In other words - ignore this behaviour, it should not be any problem.


Note - if you don't release an object (eg. keep it in a list / array / other collection) then memory associated with that object will never be released even if the system starts getting low on memory.
0
 
James AtkinSenior Principle Software EngineerCommented:
Hi,

If you are interested to see exactly what is using the memory, there is a tool I have used in the past...
http://www.red-gate.com/products/dotnet-development/dotnet-developer-bundle/
It is not free if you want to continue to use it, but if memory serves I think there is a 2 or 4 week evaluation that is more than enough time for one-offs ;-)

James
0
Cloud Class® Course: CompTIA Cloud+

The CompTIA Cloud+ Basic training course will teach you about cloud concepts and models, data storage, networking, and network infrastructure.

 
CodeCruiserCommented:
How much memory is your app using? Are you using any datatables or other similar controls?
0
 
AntonioRodrigoAuthor Commented:
@CodeCruiser: yes, I am using DataTables, data readers. I am saving word documents to database. Interesting part is that when I open word document and fill this document with data, memory usage grows about 16MB. Even when I close the document, increased RAM usage stays.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
From my earlier comment.

That is because the GC mechanism will only release memory when it determines it is necessary, not when an object is no longer in use.
0
 
CodeCruiserCommented:
Do you release all the resources properly after using them? Use the Dispose() method as much and as soon as you can.
0
 
deightonprogCommented:
.net apps can get memory leaks - is the increase in memory generally continuous and unbounded? - if you run your program indefinitely, does it ultimately run out of memory?  

I had this issue due to a third party control, and they told me the 'garbage collection is being awaited', but that was not correct on their part.

If though memory is utilised and you eventually seem to get it back, then this is often normal.

A third issue can be failing to dispose of unmanaged resources, if you fail to call the .dispose method on certain objects, it can lead to temporary or permanent trouble.

0
 
deightonprogCommented:
BTW, if you are processing large word documents, you might just be growing the large object heap

http://msdn.microsoft.com/en-us/magazine/cc163491.aspx
0
 
AntonioRodrigoAuthor Commented:
I've figured it out at least part of my problem: majority of RAM usage is unmanaged, which is not cleaned by garbage collector. The problem I have now is to find out how this could happen? I was always thinking that .NET applications are using just managed part of the RAM and all the objects are released by GC sooner or later. How can .NET app using so much of the unmanaged RAM? I have a desktop application, Windows Forms, Visual Studio 2010, Win 7.

 Unmanaged RAM usage is more than 80%
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
From my first comment:
Note - if you don't release an object (eg. keep it in a list / array / other collection) then memory associated with that object will never be released even if the system starts getting low on memory.

At a guess you are keeping hold of objects that use unmanaged memory - and you have later said you are doing things with word, maybe you aren't releasing after using it.  

The comment #37262684 from deighton (Large Object Heap) might also be relevant - the GC doesn't clean the LOH.


However your pie chart shows usage of about 45 MB which is small - does it increase by this ammount each time you do something with a word document ?
0
 
AntonioRodrigoAuthor Commented:
Unmanaged heap is increasing even when I'm opening forms (and closing them). It increases and stays on increased amount.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
By how much is it increasing?  (What controls do you have on the form?  Does it run any code during during the opening/closing ?)
0
 
AntonioRodrigoAuthor Commented:
It is increasing by approximatelj 1MB. I have tab control on my form, combo boxes and datagrid. Form is connecting to the database and filling datagrid and comboboxes through connector class.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I suspect this is perfectly normal operation.  The memory usage is probably not enough to get the GC mechanism to kick in a clean up (reorganise) the memory your app uses.  

I'd suggest open and close the form a number of times, note the memory usage.  Then open numbers of other apps (to try to use a lot of memory) such as photoshop or other picure editors and see if the memory footprint of your app drops.  Also see just how much memory is being used / available for usage (task manager).
0
 
AntonioRodrigoAuthor Commented:
I've found out what is causing memory leak in practically every win forms app: let's say I have a form. On that form, I have a button. With the click on the button, it opens a new form. When I close that form, whole form stays in RAM - with the only reference on it button_click event. As long as there is only one reference to the object, it won't get garbage collected. So, when I close the second form, it stays in RAM through button_click event. Of course I have a dispose method implemented on form_closing event - but object doesn't get garbage collected as long as there is at least one reference to it - and that reference in button_click.

And here's the problem: how to remove button_click event? I've tried:

this.button1.Click -= new System.EventHandler(this.button1_Click);

I put this event on another button_click event just for testing purposes and took another memory snapshot - the memory with all the instances of objects which that event touched stayed in memory. Nothing changed.

So how to free the memory from no longer needed objects?
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
>>So how to free the memory from no longer needed objects?

You can call gc.Collect (it might be not quite that) BUT it is not to be recommended.  Let the garbage collector mechanism run when it determines it is necessary.
0
 
AntonioRodrigoAuthor Commented:
Yes, I know for GC.Collect(). But the problem is default windows forms working - new forms opened through events stays in RAM even when you close them -> the only reference to them is the event through which they are opened and that event is causing GC not to free up the memory.

That's my main question / problem - how to free up memory when I open new form through let's say button_click?
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
>>That's my main question / problem - how to free up memory when I open new form through let's say button_click?


You can call gc.Collect (it might be not quite that) BUT it is not to be recommended.  Let the garbage collector mechanism run when it determines it is necessary.


Put another way.  The ONLY way is to call gc.Collect once all references to the object are no longer in scope.  However this results in a reorganisation of the memory in use - objects are moved in memory - so it is resource hungry.
0
 
AntonioRodrigoAuthor Commented:
>>once all references to the object are no longer in scope.

Andy thanks for answer, you've made things a little clearer for me. My biggest problem is that not all references to the form opened through click event are cleared -> reference from click event is still present. That is why GC cannot free that object from memory.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Just to be certain of what we are talking about.
This click event - is it in the form you open/close or the button event you use to create the form you open and close ?
0
 
AntonioRodrigoAuthor Commented:
It's the button event I use to create the form I open.

I've put on the newly opened form FormClosing event and Dispose form and controls on that form -> but GC cannot dispose those objects because they are referenced by click event, which opened the form. I don't have JetBrains memory profiler on this computer, so I can't post the snapshot of the RAM (I'll do it in the morning).

From the snapshot it's easy to see that when you close the form, it stays alive in the RAM through click event (as a reference on the form) from the form which opened that new form.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Could you post the code in that click event please.
0
 
AntonioRodrigoAuthor Commented:
Here's the whole class:

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 frm = new Form2();
            frm.Show();
        }
    }
}
0
 
AntonioRodrigoAuthor Commented:
And here you can see how the Form2 stays in the memory even if I close it. It's linked through Form1 button1_click event:

 Form2 stays in memory even after closing referenced by button1_click event
0
 
CodeCruiserCommented:
How are you closing form2?
0
 
AntonioRodrigoAuthor Commented:
I am closing form2 by pressing X on the top right corner.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
From my very first comment:
That is because the GC mechanism will only release memory when it determines it is necessary, not when an object is no longer in use.


The object does not exist after it is closed.  There is no reference left to it.  What you are seeing is the gc mechanism determines there is enough memory available and to clean memory will cost more effort than it brings.

Leave this alone - you are wasting your time, it is normal behaviour.
0
 
AntonioRodrigoAuthor Commented:
Andy once again thanks for answer. I know that from my question I haven't provided all the details necessary to fully understand the problem.

The app is running on the server (Citrix). Clients are just receiving image of what's happening on the server (so, server gives to each client some amount of his RAM). My app has a lot of forms. So - for each form opened (for each client) it stays in server's memory. When there is 100 clients using that app simultaneously, server memory gets quickly filled up.

But, I can understand that this is normal behaviour. If there's nothing I can do about it, I'll simply tell our customers that's just the way it is. For now, they are solving this problem in the way they periodically restart app - so RAM is cleared and slowly filled again.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
I've done the following.

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 1000; i++)
            {
                Form2 f = new Form2();
                f.Show();
                l.Add(f);
            }
            MessageBox.Show("Completed");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            for(int i = 0; i < l.Count; i++)
                l[i].Close();
            l.Clear();

            MessageBox.Show("FormsClosed");

        }

Open in new window



I click button 1 - lots of forms are displayed.  Memory drops significantly.
I then click button 2 - the forms are closed.  Memory is released.

You have some problem BUT I don't think it is what you are asking about.  Try the above code yourself in a simple win forms app.
0
 
AntonioRodrigoAuthor Commented:
Can you please post what is 'l'? Is it array list? I can't call Close on ArrrayList.

Can you post whole class?
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Sorry, I didn't think to include that.  :-(
Here is the complete class, the form2 is just a form with a listview containing a few hard coded items - not important, just adds some more to the memory required for the form.


    public partial class Form1 : Form
    {
        List<Form2> l = new List<Form2>();

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 1000; i++)
            {
                Form2 f = new Form2();
                f.Show();
                l.Add(f);
            }
            MessageBox.Show("Completed");
        }

        private void button2_Click(object sender, EventArgs e)
        {
            for(int i = 0; i < l.Count; i++)
                l[i].Close();
            l.Clear();

            MessageBox.Show("FormsClosed");

        }
    }

Open in new window

0
 
AntonioRodrigoAuthor Commented:
When I've started application with your code, my app was using 20.800 Mb of RAM.

Pressing button1 -> 29.144 Mb
Pressing button1 -> 29.112 Mb

I was pressing button1 and button2 for several times - but memory usage stays the same. It increases very little. Only if I press button1 two times and then button2 -> in that case memory usage increases to 35Mb and stays there.

I was observing RAM through task manager. Your memory usage after hitting button2 drops to the level when you've started application?
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
>>Your memory usage after hitting button2 drops to the level when you've started application?

Yes.  Like I said I put something onto the second form to take up some memory but it was all released when the forms were closed.
0
 
AntonioRodrigoAuthor Commented:
This is really strange... I am using Win 7.

We are using the same code, but experiencing different behaviour.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
Yes and no.
The principle is that memory does drop after forms are closed - on both our systems.  Your problem isn't the form closing - it is something else.
0
 
AntonioRodrigoAuthor Commented:
I've tried your code in four computers - two of them Win7, two WinXP. The memory doesn't drop.

For observing memory I was using task manager, column Working set (memory). Were you using the same program / column?

I guess this is really default behaviour and since RAM in .NET cannot be accesed directly it's really questionable whether or not this can be changed.
0
 
AndyAinscowFreelance programmer / ConsultantCommented:
>>I've tried your code in four computers - two of them Win7, two WinXP. The memory doesn't drop.

? odd - it does work here on Win 7.  Unless your machine has more memory available than mine and the GC kicks in to free memory on my system.


I did check memory with task manager AND with the resource monitor (tab: memory).  Both show an increased memory usage whilst the forms are shown and a corresponding drop when released.

>>I guess this is really default behaviour and since RAM in .NET cannot be accesed directly it's really questionable whether or not this can be changed.

Actually one can access memory directly in .net - but it really isn't recommended.
One can force the garbage collector to run by calling Collect on it.
0
 
AntonioRodrigoAuthor Commented:
I've found the code which makes RAM usage much smaller. I'm not at work at the moment, so I'll paste it tomorrow.
0
 
AntonioRodrigoAuthor Commented:
I've received this code a few days ago and it completely solves the problem.
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.