Garbage Collector

J

John Roberts

Hi,

We are developing a product with Windows CE.NET that uses compact framework
for its UI. I've been impressed with speed, etc, so far, but just started
looking at memory requirements.

We have a form that pops up a menu for the user (this is actually a child
form) which can be dismissed by the user. If the menu is poped up and then
dismissed about 20 times, the application has allocated close to the
available memory (about 24Mb) and thereafter runs out of memory and quits
with an 'out of memory exception'.

It appears that no garbage collection is invoked at all and the app just
dies instead.

However, if an application switch occurs, then a GC does happen and the
memory requirement never rises above a reasonable level.

I've read that application switches trigger GCs, as do various other events.
However, in this scenario the application just eats RAM until it dies and
never GCs. This is surely a flaw in the CF?

By the way, calling GC.Collect() after the popup is dismissed fixes the
problem. There is also no noticable performance hit.

I've read a lot about 'let the GC just do its stuff, it is highly optimised
blah blah' but from my findings, it is clearly not. Perhaps my usage pattern
is unusual. Does anyone else have any similar situations? The popup menu is
implemented as a child form.

- John
 
G

Ginny Caughey [MVP]

John,

I don't know if this addresses your exact situation but here's a general
list of what events can cause the garbage collector to get triggered:

1. An app needs more managed memory and there isn't some available to draw
from without a collection.
2. After 750K has been allocated.
3. The app goes into the background. (Your switching apps scenario.)
4. An unmanaged allocation in the .NetCF execution engine fails.

With each new version of the CF, the developers look at additional ways to
tune the garbage collector behavior, so this list could change in the
future. For example, sometimes when an allocation for an underlying OS
resouce (such as GDI) fails, the GC might get triggered too.
 
A

Alex Feinman [MVP]

You could try calling Dispose on your menu form after you are done with it,
or alternatively keep the instance reference and reuse it
 
J

John Roberts

Thank you for your response (and the others too).

I've looked into this some more and have made the following observations.

First, if I monitor the amount of memory that the GC says it has using
GC.GetTotalMemory(false), it naturally goes up after each show/close of the
form (by the way, I do call Dispose on the form). It goes up by about 30k.
However, the amount of memory the application has actually allocated itself
(according to performance monitor) goes up by about 1Mb. It does this each
time the form is displayed. Soon, GC.GetTotalMemory(false) returns figures
in the order of 300k but the process has swallowed up 24Mb of RAM.

When system RAM is finally exhauseted, there is a 'blip' where the process
releases about 1Mb of RAM. I assume this is some type of collection
triggered by an out of memory exception. However, the collection doesn't
appear to be as 'complete' as a GC.Collect() because two more form displays
later and the process throws out of memory exceptions and dies.

I'm guessing that because GetTotalMemory(false) doesn't get larger than
750k, a collection is never triggered. The scenario you mention below as '4'
may happen when memory is exhausted, but it doesn't free up the full amount
of process memory. If '3' happens then yes, everything is freed although the
process still appears to hold on to the maximum amount it allocated (it's
not easy to confirm this because CE heap is lazy in freeing up memory).

If other types of object are allocated in a similar usage pattern, the the
GC behaves as expected although GetTotalMemory(false) goes up to about 1Mb
before a collection is triggered.

Therefore, this problem seems to be particular to a child form. If I had to
take a stab at guessing the cause - something else is being allocated per
form - something big - and something which doesn't 'count' in
GetTotalMemory. It does get deallocated when a collection runs but
unfortunately, not in scenario 4. Therefore, physical memory runs out before
a collection is triggered.

I realise this problem can be 'managed' by recycling the form or forcing a
GC when it is closed. However, its worth discussing because I think its a
bug that should be fixed in future versions.

This is my first 'run in' with the CF. I hope there aren't any more because
I'm basing all our software development efforts on it! Otherwise, the CF is
an impressive piece of technology.

- John
 
D

Daniel Moth

Have you looked at the performance counters? Maybe they can offer some
clues...
http://groups.google.com/groups?hl=...soft.public.dotnet.framework.compactframework

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetcomp/html/netcfperf.asp

Also try with SP3 Beta (assuming you are already using SP2)
http://blogs.msdn.com/onoj/articles/178293.aspx
From its fix list:
GUI memory leak under some conditions

Finally you can try with the CF 2.0 Beta (part of VS2005 Beta 1 from msdn
subscriber downloads)

If none of the above help then please post a small sample that reproduces
the problem

Cheers
Daniel
 
J

John Roberts

Thanks for your reply. Performance counters confirm that a GC is not being
triggered.

I'm using the CF v1.1 . I assume that superceeds CF 1.0 SP3 ? The actual
version of mscoree.dll is 1.0.5000.0 and I assumed it was the latest.

I'd love to try the beta of CF 2.0 but our project is due out before this is
likely to be released. Unless you know when it will be released - 2005 I
guess...?

I will try to come up with a sample.

Cheers,
- John
 
J

John Roberts

OK, I have tried SP3 which seems to behave better when the memory is
exhausted.

Now, when all memory is used up, Windows CE.NET pops up 'memory is low'
warning dialog box a couple of times. However, the CF doesn't crash so some
garbage collection must be going on. It isn't a 'full collect' though
because the memory remains tight and GetTotalBytes returns something in the
order of 500k

Repeating this continues (complete with low memory warning) until a full
garbage collect is finally triggered - persumably by the 750k trigger. Then,
the process seems to release a _big_ chunk of memory from the CE heap. By
big I mean something in the order of 20Mb.

So, it looks like it is behaving as designed. However, I'm a bit concerned
that the process memory can grow to 24Mb when the managed heap only reports
500k of data in it. Also, it seems strange that hitting the bounds of
available physical memory doesn't cause a 'full' collection - that is
reserved for a task switch or the 750k limit in the managed heap.

It seems to me that the CF should trigger a collection more regularly or
using some additional criteria.

Is there a way to stop the 'low memory' warning from popping up?

Cheers,
- John
 
D

Daniel Moth

Is there a way to stop the 'low memory' warning from popping up?

That would only hide the problem, not fix it... What device are you running?
If you are in control of your platform (i.e. using platform builder), you
can remove the OOM component from your image.. Also look at the SetOomEvent
and the HKLM\SYSTEM\OOM reg settings...
http://msdn.microsoft.com/library/d...n40/html/cmconoomthresholdmigrationissues.asp

However, I'd suggest producing a small sample that demonstrates the problem
and posting it here... Someone from the group or from MS should be able to
help...

Cheers
Daniel
 
J

John Roberts

Hi Daniel,

Thank you for making me confront my demons. I wrote a sample application
which didn't exhibit the problem. I then discovered a bug in my code which
was erroneously allocating a handful of bitmaps and then 'leaking' them
without calling Dispose(). Therefore, the heap (where the bitmaps are, I
guess) was growing proportionally larger than the managed heap itself. Of
course the bitmaps ultimately get cleaned up by the garbage collector but
physical memory ran out before the managed heap hit the 750k magic number.

I guess it has demonstrated that the garbage collector in SP3 handles
low-memory conditions better than in SP2. In fact, SP2 crashes wereas SP3
copes.

Maybe the CF developers could consider triggering using additional criteria
such as the size of the unmanaged heap, for example.

Thanks also for the links on OOM. I am in control of the platform and so the
OOM warning will probably have to be removed.

Kind regards,
- John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top