Chris.G

Hi !

What could explain that the instance of 'MyControl' is not garbage collected even though !dumpheap shows that there is no longer any strong reference to it
To put this in evidence I inserted a loop calling GC.Collect and a breakpoint at which I'm running !dumpheap.

What is even stranger to me is that 'MyControl' gets eventually collected, but later (after exiting Main).
This is annoying since 'MyControl' holds unmanaged memory and I'd like to check that I have no unmanaged memory leaks. This very late garbage collection causes inevitably false detections.

Chris.

------
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Application.Run(new MyFirstForm());


for (int n = 0; n < 100; n++)
{
GC.Collect();
GC.WaitForPendingFinalizers(); // <- breakpoint here
}
}

DOMAIN(005E1648):HANDLE(WeakLn):a1054:Root:028a620c(System.Windows.Forms.NativeMethods+WndProc)->
028a6100(System.Windows.Forms.Control+ControlNativeWindow)->
028a602c(MyNamespace.MyControl)->
028a5e78(System.Windows.Forms.TableLayoutPanel)->
028a5f2c(System.Windows.Forms.PropertyStore)->
028b3798(System.Windows.Forms.PropertyStore+ObjectEntry[])->
028aaaa4(System.Windows.Forms.Layout.TableLayout+ContainerInfo)->
028b3724(System.Object[])->
028aabcc(System.Windows.Forms.Layout.TableLayout+LayoutInfo)->
028a6344(System.Windows.Forms.TableLayoutPanel)->
028a63f8(System.Windows.Forms.PropertyStore)->
028b38ec(System.Windows.Forms.PropertyStore+ObjectEntry[])->
028aaf08(System.Windows.Forms.Layout.TableLayout+ContainerInfo)->
028b3850(System.Object[])->
028ab074(System.Windows.Forms.Layout.TableLayout+LayoutInfo)->
028a7918(System.Windows.Forms.GroupBox)->
028a798c(System.Windows.Forms.PropertyStore)->
028b2d40(System.Windows.Forms.PropertyStore+ObjectEntry[])->
028aba5c(System.Windows.Forms.Control+ControlCollection)->
028aba70(System.Collections.ArrayList)->
028aba88(System.Object[])->
028a7a28(System.Windows.Forms.TrackBar)->
028abaa8(System.ComponentModel.EventHandlerList)->
028abafc(System.ComponentModel.EventHandlerList+ListEntry)->
028abab8(System.EventHandler)->
028a5074(MyApp.MySecondForm)->
02896354(MyApp.MyFirstForm)->
02898d38(MyNamespace.MyControl)
DOMAIN(005E1648):HANDLE(WeakLn):a105c:Root:0289f590(System.Windows.Forms.NativeMethods+WndProc)->
02899e18(System.Windows.Forms.Control+ControlNativeWindow)->
02899d48(System.Windows.Forms.Button)->
0289a960(System.ComponentModel.EventHandlerList)->
0289b14c(System.ComponentModel.EventHandlerList+ListEntry)->
0289b12c(System.EventHandler)->
02896354(MyApp.MyFirstForm)
DOMAIN(005E1648):HANDLE(WeakLn):a1060:Root:0289f570(System.Windows.Forms.NativeMethods+WndProc)->
02899ccc(System.Windows.Forms.Control+ControlNativeWindow)->
02899bfc(System.Windows.Forms.Button)->
0289a92c(System.ComponentModel.EventHandlerList)->
0289b0e0(System.ComponentModel.EventHandlerList+ListEntry)->
0289b0c0(System.EventHandler)->
02896354(MyApp.MyFirstForm)
DOMAIN(005E1648):HANDLE(WeakLn):a107c:Root:0289f348(System.Windows.Forms.NativeMethods+WndProc)->
02897e34(System.Windows.Forms.Control+ControlNativeWindow)->
02897d64(System.Windows.Forms.Button)->
0289ab04(System.ComponentModel.EventHandlerList)->
0289acf8(System.ComponentModel.EventHandlerList+ListEntry)->
0289acd8(System.EventHandler)->
02896354(MyApp.MyFirstForm)
DOMAIN(005E1648):HANDLE(WeakLn):a108c:Root:0289f224(System.Windows.Forms.NativeMethods+WndProc)->
028979b0(System.Windows.Forms.Control+ControlNativeWindow)->
028978ec(System.Windows.Forms.TableLayoutPanel)->
028979a0(System.Windows.Forms.PropertyStore)->
0289f964(System.Windows.Forms.PropertyStore+ObjectEntry[])->
0289a844(System.Windows.Forms.Layout.TableLayout+ContainerInfo)->
0289f8c8(System.Object[])->
0289a908(System.Windows.Forms.Layout.TableLayout+LayoutInfo)->
02898d38(MyNamespace.MyControl)
DOMAIN(005E1648):HANDLE(WeakLn):a1098:Root:0289c888(System.Windows.Forms.NativeMethods+WndProc)->
02896554(System.Windows.Forms.Control+ControlNativeWindow)->
02896354(MyApp.MyFirstForm)
DOMAIN(005E1648):HANDLE(WeakLn):a10b4:Root:02899124(System.Windows.Forms.NativeMethods+WndProc)->
02898e0c(System.Windows.Forms.Control+ControlNativeWindow)->
02898d38(MyNamespace.MyControl)
DOMAIN(005E1648):HANDLE(WeakSh):a129c:Root:02898e0c(System.Windows.Forms.Control+ControlNativeWindow)
DOMAIN(005E1648):HANDLE(WeakSh):a12dc:Root:02896554(System.Windows.Forms.Control+ControlNativeWindow)



Re: Common Language Runtime Why isn't my object garbage collected ?

.NETPhreak

This is one of those "click" moments... I used to ponder about the same question. You have to dig a bit deeper to try and understand what is going on at the CLR level - garbage collections occur at allocation time, NOT when you call GC.Collect(). This is one of those built-in, CLR-level enhancements Smile. So calling GC.Collect will do you no good if there is enough space in gen0.

Some of the points I made above are too generalized, and before people start kicking me, I would like to point that this was a quick reply. In short, your GCs happen at allocation time.

By the way, why the hell are you calling GC.Collect




Re: Common Language Runtime Why isn't my object garbage collected ?

Rob Teixeira

There could be a number of issues at stake here. For example, GC works on generation levels, and objects created early on in the app are mostly moved to a generation that is assumed to be long-living.

But the real issue you have to be concerned about is that you should never depend on GC to free unmanaged memory. Unmanaged memory should be used in the smallest possible scope (local method variables, which are immediately freed before the end of the method). In the case of components like controls, where the unmanaged memory is required for a longer scope, you should never depend on finalize or GC to do anything about that unmanaged memory. Make sure that the control properly implements IDisposable and that the form is closed properly (which should invoke Dispose()). That's really the whole purpose of Dispose - to free unmanaged resources independantly of the GC so you don't have to worry about GC cycles, and the unmanaged memory can be freed on a determinate basis.






Re: Common Language Runtime Why isn't my object garbage collected ?

nobugz

You posted the boring bit. The interesting bit would be to see what is going on inside the form. You've got plenty of controls by the look of it. Why don't you pare it down, removing controls one after another, until you've found the minimum app that you think that leaks, then post again.





Re: Common Language Runtime Why isn't my object garbage collected ?

Chris.G

Thanks for your efforts, but your answers are not very useful.

Why am I calling GC.Collect() Just read the documentation of GC.WaitForPendingFinalizers() (and the example) and you'll see that it's supposed to do something.

I should never depend on GC to free unmanaged memory I never expected nor wrote that. The fact is that my control relies on native libraries and thereby holds unmanaged memory. Tracking unmanaged memory leaks would be much easier if I could ensure at some point that all the managed objects no longer referenced have actually been finalized (so that my managed objects can free their native resources).

I posted the boring bit All I want to understand is why the garbage collector does not collect objects that only show WeakLns, and WeakShs. That's all. I'll be happy with a link to an URL that will help me understand this.

Chris.





Re: Common Language Runtime Why isn't my object garbage collected ?

.NETPhreak

Well... You did not post any major details of what your code is based off of. Also, if you look at the MSDN documentation, http://msdn2.microsoft.com/en-us/library/system.gc.waitforpendingfinalizers.aspx, I don't see how that relates to what you described.

Maybe this will help you: http://blogs.msdn.com/tess/archive/2007/04/10/net-garbage-collector-popquiz-followup.aspx

Here is more: http://msdn.microsoft.com/msdnmag/issues/1100/GCI/ & http://msdn.microsoft.com/msdnmag/issues/07/07/CLRInsideOut/default.aspx

Again, the managed world doesn't know anything about your unmanaged resources. It doesn't know how to free them. Hence, IDisposable. Calling GC.Collect and expecting it to collect unmanaged resources will do you no good.





Re: Common Language Runtime Why isn't my object garbage collected ?

Chris.G

ok. Thanks for the links.

Probably I introduced confusion by talking about unmanaged memory (which is only a side effect of the problem). So, let's forget about it and just talk about managed code. The one thing that I do not understand is why an object for which !dumpheap shows only WeakLns and WeakShs does not get collected the next time(s) garbage collection is forced I am aware that the documentation says "the Collect method does not guarantee that all inaccessible memory is reclaimed", but this doesn't tell much: why some objects are collected and other not Hopefully I'll find the answer in the links you provided.

Chris.





Re: Common Language Runtime Why isn't my object garbage collected ?

Pravin Chandankhede

Hi chris..

i woyld like to know what kind of unmanged resouce you are dealing with..... is it a COM obejct or an operating system resoucres like ports...

if you are directly dealing with the COM obejcts , try calling System.Runtime.InteropServices.ReleaseCOMObejct so that all the refrences to ur unmanged obejct will be relased and after that you can call GC.Collect to finally collect the managed object that holds reference to ur unmanged object.... what i think is happenign is ur COM object si alive and thus the reference to it(the managed object) is also alive......

just collecting the FORM obejct will not sove ur problem... its problem related to the objects contained within forms.