Using RPM I identified that dynamically creating controls are not garbage collected as expected. Running the same piece of code in .NET Window Forms behave differently and disposes the control as I expected.

See the output from RPM via PerfMon for the Process Heap counter:

GC Heap:

My best guess is that the Weak Reference to the Panel is for some unknown reason not making the object eligible for GC, can it be?

Please note: Even though Dispose() solves the problem for the sample, I can't easily incorporate it into the existing application as it is not as clear cut to determine when the object is no longer in use.

I have included a simplified version of the source to illustrate the problem:

4 Answers
4

Everything UI related on NETCF is
intentionally removed from GC scope so
it is never collected. This behavior
is different from desktop and has been
changed in NETCF V3.5 (unless running
in compatibility mode).

It is so different because managed UI
classes on NETCF are completely
different from desktop. They are thin
wrappers over native implementation
which was needed to achieve acceptable
performance.

I’m not sure there’s such a resource.
But really, all you need to know is:
it’s never collected, must call
dispose. You actually should do that
on desktop as well but if you don’t
its way more forgiving. Not so on
NETCF.

A Form does not automatically Dispose all Controls created in its code, as it has no way to know it exists. To get the Form to Form to Dispose it automatically when it's Disposed, you need to add it to the Controls collection.

Now in your case that may not do anything. I can't tell if your example is contrived, or real world. If it's real-world, then the behavior is expected, as the Panel doesn't get collected when the variable goes out of scope (not sure it does on the desktop either). It becomes available for collection, but that simply means that on the next collection pass it will be swept. Unless you're causing a GC, then it's not going to be freed.

I'd highly recommend you take a look at the MSDN webcast on memory management in the CF. It provides a much more thorough explanation as to what's happening under the hood - far more than we could provide in an answer here.