I'm trying to access the performance counters located in ".NET CLR Memory category" through C# using the PerformanceCounter class. However a cannot instantiate the categories with what I would expect was the correct category/counter name
new PerformanceCounter(".NET CLR Memory", "# bytes in all heaps", Process.GetCurrentProcess().ProcessName);
I tried looping through categories and counters using the following code
string[] categories = PerformanceCounterCategory.GetCategories().Select(c => c.CategoryName).OrderBy(s => s).ToArray();
string toInspect = string.Join(",\r\n", categories);
System.Text.StringBuilder interestingToInspect = new System.Text.StringBuilder();
string[] interestingCategories = categories.Where(s => s.StartsWith(".NET") || s.Contains("Memory")).ToArray();
foreach (string interestingCategory in interestingCategories)
{
PerformanceCounterCategory cat = new PerformanceCounterCategory(interestingCategory);
foreach (PerformanceCounter counter in cat.GetCounters())
{
interestingToInspect.AppendLine(interestingCategory + ":" + counter.CounterName);
}
}
toInspect = interestingToInspect.ToString();
But could not find anything that seems to match. Is it not possible to observe these values from within the CLR or am I doing something wrong.
The environment, should it matter, is .NET 4.0 running on a 64-bit windows 7 box.
Counters are per instance. Try adding:
You need to run the program as Administrator to access .NET CLR Memory category.
Try this simple test, using powershell:
When running as Administrator
When running without administrative privileges:
It should work. Note that as others have already set, the CLR counters are per instance counters, thus you need to specify the instance name for the process you wish to query the counters for.
So the statement you specified at the top of your post should work. However, you should also use the constructor overload that allows you to specify that you wish to access the instance in "read-only" mode:
The second code fragment you posted does not work, as you didn't specify an instance name to the
GetCounters()
operation. Use theGetCounters(string instanceName)
overload instead and it should work.Finally, note that the instance name is not necessarily the same as
Process.ProcessName
(orProcess.GetCurrentProcess().ProcessName
for that matter). If there are multiple instances of a process, i.e. executable, the process name is created by appending a#<number>
. To figure out the actual instance name of a process you should query the.NET CLR Memory\Process ID
counter.Example:
The instance name you gather by this method is good for performance counters in other ".NET CLR" categories as well.
Update: Added mitigation for potential race condition between the time we gather the potential instance names and the time we peruse them. A .NET process (for which we've seen an instance name) might no longer be there (and such the instance is also gone) when we try to use it.