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.