Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / Performance / February 2004

Tip: Looking for answers? Try searching our database.

PerformanceCounter handle leak

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Jerry Pisk - 21 Jan 2004 00:49 GMT
I was wondering if someone came across a handle leak when using
PerformanceCounter class. My code comes down to doing this:

PerformanceCounter Counter = new PerformanceCounter("CategoryName",
"CounterName", "InstanceName");
CounterSample        Sample = Counter.NextSample();
// Dump the sample values here
Counter.Close()

Each time this runs about 10 handles are not released until the next garbage
collection. This is causing some serious problems since I'm collecting 10+
counters each time. Is there a way to release those handles as soon as I'm
done using the counter? I mean, my process is using upwards of 5,000 handles
before GC kicks in and cleans them up... If I do not collect the counter
samples I'm running at less than 200 handles in the same process.

Thanks

Jerry Pisk
Ryan Byington - 21 Feb 2004 02:07 GMT
Unless you have a verry compelling reason the pattern of creating a new
PeformanceCounter just to call NextSample on it then destroying it should
not be done. This is because creating a new PerformanceCounter is not a
trivial ammount of work. Also some counter types require two CounterSamples
to calculate the value and if you only have one CounterSample the
calculated value will be zero for these counter types.

I have tried to get the handle count to increase per new performance
counter created and I have not been able to reproduce this. If  you post
some more repro steps and the version of the runtime that your are using I
can look into this further for you.

Ryan Byington [MS]

This posting is provided "AS IS" with no warranties, and confers no rights.
Use of included script samples are subject to the terms specified at
http://www.microsoft.com/info/cpyright.htm

--------------------
| From: "Jerry Pisk" <jerryiii@hotmail.com>
| Subject: PerformanceCounter handle leak
[quoted text clipped - 8 lines]
| NNTP-Posting-Host: 12.173.163.30
| Path:
cpmsftngxa07.phx.gbl!cpmsftngxa10.phx.gbl!TK2MSFTNGXA05.phx.gbl!TK2MSFTNGP08
.phx.gbl!tk2msftngp13.phx.gbl
| Xref: cpmsftngxa07.phx.gbl
microsoft.public.dotnet.framework.performance:6441
| X-Tomcat-NG: microsoft.public.dotnet.framework.performance
|
[quoted text clipped - 17 lines]
|
| Jerry Pisk
Jerry III - 21 Feb 2004 18:34 GMT
I do have a compelling reason to do this - the object that reads the
counters is created and destroyed each time it reads them since it's an
Asp.Net page.

Also, I use raw counter values and do my own calculations on the client
since multiple users can request the counters at the same time (which might
throw off the calculated counter values on the server).

Jerry

> Unless you have a verry compelling reason the pattern of creating a new
> PeformanceCounter just to call NextSample on it then destroying it should
[quoted text clipped - 27 lines]
> | NNTP-Posting-Host: 12.173.163.30
> | Path:

cpmsftngxa07.phx.gbl!cpmsftngxa10.phx.gbl!TK2MSFTNGXA05.phx.gbl!TK2MSFTNGP08
> phx.gbl!tk2msftngp13.phx.gbl
> | Xref: cpmsftngxa07.phx.gbl
[quoted text clipped - 22 lines]
> |
> | Jerry Pisk
- 23 Feb 2004 07:03 GMT
Can you post reproducable code showing this? I.e. code
that anyone can copy/past and run directly, that makes
it easier to understand your problem. I didn't manage
to reproduce it.

I'm not convinced your usage scenario is a compelling
reason to create and destroy counters all the time, but
then I don't know the full scenario. Can the user selecy
any random counter to display, or is it some restrictede
set of counters?

If you can describe the problem a bit more detail, we
might come up with an alternative solution. Creating
counters all the time is relatively painful, so you
really want to avoid it if possible.
Jerry III - 23 Feb 2004 20:43 GMT
Here's the page code:

-----------------------------------------------------------------------
<%@ Page Language="C#" ContentType="text/xml" %>
<%@ Import namespace="System.Diagnostics" %>
<%@ Import namespace="System.Xml" %>
<script language="C#" runat="server">

static int PERF_TYPE_NUMBER  = 0x00000000;  // a number (not a counter)
static int PERF_TYPE_COUNTER  = 0x00000400;  // an increasing numeric value
static int PERF_TYPE_TEXT   = 0x00000800;  // a text field
static int PERF_TYPE_ZERO   = 0x00000C00;  // displays a zero

static int PERF_COUNTER_VALUE  = 0x00000000;  // display counter value
static int PERF_COUNTER_RATE  = 0x00010000;  // divide ctr / delta time
static int PERF_COUNTER_FRACTION = 0x00020000;  // divide ctr / base
static int PERF_COUNTER_BASE  = 0x00030000;  // base value used in
fractions
static int PERF_COUNTER_ELAPSED = 0x00040000;  // subtract counter from
current time
static int PERF_COUNTER_QUEUELEN = 0x00050000;  // Use Queuelen processing
func.
static int PERF_COUNTER_HISTOGRAM = 0x00060000;  // Counter begins or ends
a histogram
static int PERF_COUNTER_PRECISION = 0x00070000;  // divide ctr / private
clock

static int PERF_TIMER_TICK   = 0x00000000;  // use system perf. freq for
base
static int PERF_TIMER_100NS  = 0x00100000;  // use 100 NS timer time base
units
static int PERF_OBJECT_TIMER  = 0x00200000;  // use the object timer freq

public void Page_Load(Object sender, EventArgs e)
{
   // Result Document
   XmlDocument PerformanceDocument = new XmlDocument();
   XmlElement PerformanceElement =
PerformanceDocument.CreateElement("performance");

PerformanceDocument.AppendChild(PerformanceDocument.CreateProcessingInstruct
ion("xml", "version=\"1.0\" encoding=\"UTF-8\""));
   PerformanceDocument.AppendChild(PerformanceElement);
   SampleSystemPerformance(PerformanceElement);

   // Render the Document
   XmlTextWriter XmlOutputWriter = new XmlTextWriter(Response.Output);

   PerformanceDocument.WriteTo(XmlOutputWriter);
   XmlOutputWriter.Close();
}

void SampleSystemPerformance(XmlElement PerformanceElement)
{
 // System Counters
 RenderCounterSample(PerformanceElement, "Processor\\% Processor
Time\\_Total");
 RenderCounterSample(PerformanceElement, "Memory\\Available Mbytes");
 RenderCounterSample(PerformanceElement, "Memory\\Pages/sec");
 RenderCounterSample(PerformanceElement, "System\\Context Switches/sec");
 RenderCounterSample(PerformanceElement, "Process\\Handle
Count\\aspnet_wp");
}

PerformanceCounter CreatePerformanceCounter(string CounterName)
{
 if( CounterName == null )
 {
  throw new ArgumentNullException();
 }

 // Create Counter
 string[]  Components = CounterName.Split('\\');

 if( Components.Length == 2 )
 {
  return new PerformanceCounter(Components[0], Components[1]);
 }
 else if( Components.Length == 3 )
 {
  return new PerformanceCounter(Components[0], Components[1],
Components[2]);
 }
 else if( Components.Length == 4 )
 {
  return new PerformanceCounter(Components[0], Components[1],
Components[2], Components[3]);
 }

 throw new ArgumentException();
}

void RenderCounterSample(XmlElement ParentElement, string CounterName)
{
 RenderCounterSample(ParentElement, CounterName,
CreatePerformanceCounter(CounterName).NextSample());
}

void RenderCounterSample(XmlElement ParentElement, string CounterName,
CounterSample Sample)
{
 XmlElement  SampleElement =
ParentElement.OwnerDocument.CreateElement("counter-sample");

 long   CounterType = (int)Sample.CounterType & 0x00000C00;
 long   CounterSubtype = (int)Sample.CounterType & 0x000F0000;
 long   TimerBase = (int)Sample.CounterType & 0x00300000;

 SampleElement.SetAttribute("counter", CounterName);
 SampleElement.SetAttribute("counter-type",
((int)Sample.CounterType).ToString("X08"));
 SampleElement.SetAttribute("raw-value", Sample.RawValue.ToString());

 if( CounterType == PERF_TYPE_NUMBER )
 {
  // The value is enough for this counter
 }
 else if( CounterType == PERF_TYPE_COUNTER )
 {
  if( CounterSubtype == PERF_COUNTER_VALUE )
  {
  }
  else if( CounterSubtype == PERF_COUNTER_RATE )
  {
   // Time
   if( TimerBase == PERF_TIMER_TICK )
   {
    SampleElement.SetAttribute("time-stamp", Sample.TimeStamp.ToString());
    SampleElement.SetAttribute("system-frequency",
Sample.SystemFrequency.ToString());
   }
   else if( TimerBase == PERF_TIMER_100NS )
   {
    SampleElement.SetAttribute("time-stamp-100nsec",
Sample.TimeStamp100nSec.ToString());
   }
   else if( TimerBase == PERF_OBJECT_TIMER )
   {
   }
  }
 }

 ParentElement.AppendChild(SampleElement);
}
</script>

Add any namespaces it needs, I didn't post the whole page for clarity so I
might have left some out. If you run this under Windows 2000 Server (NOT
Win2k3, it works fine there) you will see that the handle count for
aspnet_wp will keep going up untill the application restarts. It eats 9
handles per counter, so feel free to add more counters to speed up the
process (Asp.Net app restarts once you get to 4 or 5 thousand handles).

And just to let you know - calling PerformanceCounter.Close on those counter
objects does not help, if you want to go ahead and change
RenderCounterSample to this:

void RenderCounterSample(XmlElement ParentElement, string CounterName)
{
   PerformanceCounter  Counter = CreatePerformanceCounter(CounterName);
   RenderCounterSample(ParentElement, CounterName, Counter.NextSample());
   Counter.Close();
}

I  eventually used WMI to gather the performance counters I need but I think
that's less than ideal solution. And of course the code is not finished, it
will not render all the information needed for all counter types but it
works for the ones I'm watching. I'll add more when I need it.

Jerry
> Can you post reproducable code showing this? I.e. code
> that anyone can copy/past and run directly, that makes
[quoted text clipped - 11 lines]
> counters all the time is relatively painful, so you
> really want to avoid it if possible.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.