Global .NET Memory Performance Counters Do NOT Work

I discovered today that the _global_ .net memory performance counters simply do NOT work.  They don't tell you anything at all about the sum total of all your .net processes.  They instead only report the last sample that was collected, regardless of the process.  This is not at all documented as far as I can tell.  In fact, the MSDN docs specifically go out of their way to say this is the behavior of only the 3 counters that track the total number of collections, implying that the others work fine.  I was heavily using the counters about the total number of bytes that .net had in its various heaps, and this is the correct usage according to the books and articles I've seen.  But they clearly don't work since you can set counters for each individual process and compare them to the global counter for yourself.  Its very frustrating to find out that all of my performance tests have been for nothing, since they assumed that the performance counters were reliable.  It also begs the question that I'm still having problems actually tracking down in Citrix (or Terminal Server) -- does the .net garbage collector understand that there are other processes also running at the same time?  Everyone without Citrix experience trys to tell me that of course the .net gc works right in Citrix, but it seems that the few other people that are trying keep having the same questions.  And now its apparent that the global .net memory performance counters are unaware of multiple processes, so . . . ?  By the way, someone from Microsoft noted that the .net gc listens to the low memory notification event to know when it needs to work.  But guess what -- the default setting for this is that your memory is low when you only have 32MB left on a 4GB server!  There's also nothing I can find anywhere that tells you how to change this default setting to something more reasonable.  That number sounds too low in any setting, but imagine a Citrix server with many users all having processes open -- when there's only 32MB left it will be far too late to do anything without severely impacting performance.

Here's another question for you .net gurus -- why does a recordset that is only 4MB in query analyzer take 24MB in a .net datatable?  And why is there another 3MB that is lost in total system available memory that isn't reflected in the .net memory performance counters for that process?  Similarly, a 7MB recordset takes 40MB in a .net datatable and a 10MB recordset takes 65MB in a .net datatable, and each always has another 3MB that seems to go missing according to the counters.  I realize there is more to a datatable than just data, and that .net allocates a large chunk than it needs, but this seems a little excessive.  By the way, this is all from testing on .net v1.1 on Windows 2003 Enterprise Server.

6 Comments

  • Have you put in an incident into Microsoft Support re: the perf counters?



    And, thanks for blazing the way in Citrix. We may be doing this kind of stuff in the future, and I'd rather see you feel the pain than me!

  • >And why is there another 3MB that is lost in total system available memory that isn't reflected in the .net memory performance counters for that process?



    What is "total system availabale memory"? There's no such counter in perfmon. Are you looking at Available Physical Memory in task manager?

  • "...memory is low when you only have 32MB left on a 4GB server" - and why exaclty would you want to have 4GB of RAM and only use half of it? A production server should have zero available memory under normal operation. If it doesn't than it's wasting your resources.

  • >A production server should have zero available memory under normal operation.



    If you have zero available (physical) memory on a production server it's definitely not normal. While some memory hungry apps like SQL Server tend to consume most of the available memory, they usually leave at least 10 MB for other processes.



    If a server consistently has less than 10 MB of physical memory available it alsmost always means lots of paging and horrible performance as a result.

  • I'm referring to the regular memory performance counter for total available memory when I mention total system available memory. That seems to reflect just available RAM, and all of it, which may not always be the best number ideally, but its certainly a far better number than the .net global one that simply doesn't work.

  • I don't know what causes the behavior that you describe, but I just wanted to say that counters like Memory\Available MBytes are not the best way to measure memory usage. Available physical memory can jump up and down depending on how the OS feels.



    If you want to measure how much memory a single process has allocated, use Process\Private Bytes. For global memory usage, use Memory\Committed Bytes.

Comments have been disabled for this content.