Memory counters have a name,f.i.Taskmanager shows 'Mem Usage' and 'VM Size'
per default. The Performance monitor has a whole bunch of named Memory
counters. So when talking about memory consumption you should add the name
of counter you are looking at. Note that "perfmon" also has a number of CLR
specific memory counters that are more important than the Taskman counters.
For the remaining of this discussion I assume you are looking at (but I
could be wrong) Taskmanager's "VM size" , which is the 'wrong' counter to
look at when talking about RAM usage.
'VM size' shows the number of "private bytes" committed to the process, that
doesn't mean all those bytes are taking up physical memory only a part of it
is actually stored in RAM. The number of bytes currently taking up RAM is
shown in the 'Mem Usage' column, this counter is the sum of the private
bytes and shared/shareable bytes currently in RAM.
Shared/Shareable bytes are those that are effectively shared or can possibly
be shared amongst other processes, a small managed program can share some
20-30% of it's 'Mem Usage' or "Working Set" with other non 'managed'
processes and up to 40-70% with other managed processes, depending on the
type of application.
What does this all mean? Suppose you have a managed process (a small
Winforms application) taking 14MB of RAM (Mem Usage),
when starting a second instance, because of code sharing, this will only
take ~30% -70% more RAM. So you can't simply add the 'Mem Usage' counters
like you did in your original posting to calculate the amount of RAM used
when running several instances.
Now why are 'VM Size' and 'Mem Usage' values higher when compared to a
native Win32 process,?
First the CLR is loaded in a managed application, this takes up some MB of
shared/shareable pages - part of it shared with non managed applications and
almost all of it shared with other managed processes.
A winforms application loads (besides other FCL assemblies like System.dll,
Mscorlib.dll etc..) a large part of the Windows.Forms.dll assembly for the
UI main window initialization, this accounts for a few MB of shareable code
pages not loaded in an unmanaged application.
And for the 'VM Size' here a large part is 'reserved' by the GC heap, note
that only a part of it is actually taking up real memory, as the CLR
pre-allocates a portion which is not completely returned when not in use.
The same effect can be observed with unmanaged applications reserving a lot
of virtual memory as part of pre-allocation of buffers. When the GC heap
runs out op space the CLR will ask the OS for more memory and the VM Size
will grow, if this is paired with a growth of 'MemUsage', it can be an
indication of a managed/unmanaged leak, when VM size grows without ever
shrinking, it is almost certain a leak.
What is the lesson learned?
- Use the permon counters (and learn what they represent) when looking at
memory consumption.
- Use the Working Set counter for the actual RAM usage (if that's important
to you).
- Use "Private bytes" counter to watch for memory leaks (together with the
CLR GC counters to make a distinction between managed/unmanaged heap).
- Learn how Memory is managed in a NT based OS.
Willy.
PS. "Mem Usage" is "Working set bytes" and "WM Size" is "Private Bytes" in
Perfmon.