SWbemRefresher - Memory Leak?

EDN Admin

Well-known member
Joined
Aug 7, 2010
Messages
12,794
Location
In the Machine
Hello,
I was wondering if someone could help. I am having a problem with a Windows Service I have written, if I enable a certain option I am seeing what I think is a memory leak. Ive looked at trying to debug this using crash dumps (the app doesnt
crash BTW, I create them using process explorer), .NET Memory Profiler and WinDbg but I am not getting far down to my lack of expertise with these products.
The piece of code causing the problem is below, if I comment the call to this code out, memory usage is fine. What I am seeing is the private bytes for the process going up and up and up. This code is called regulairly and after 24 hours the
private bytes for the process are huge (say 2GB) wheras if I comment the call to this code out the private bytes remain at around 160MB, fluctuating up and down as expected.
I am not entirely sure if I am disposing of everything correctly (I think I am) and I just cant find whats causing the problem.
Here is the code:


<div style="color:Black;background-color:White; <pre>
<span style="color:Green; //CREATE REFRESHER FOR OUR CPU USAGE
<span style="color:Blue; Dim intProcessIDPre, intProcessorUsage <span style="color:Blue; As <span style="color:Blue; Integer
<span style="color:Blue; Dim strProcessName, strUserName <span style="color:Blue; As <span style="color:Blue; String
<span style="color:Blue; Dim intPrivateBytes <span style="color:Blue; As <span style="color:Blue; Double

<span style="color:Blue; Try

<span style="color:Green; //SET OURSELVES AS MONITORING
MonitoringProcesses = <span style="color:Blue; True

<span style="color:Blue; Do <span style="color:Blue; While DateTime.Now < StopTime

<span style="color:Blue; Dim objRefreshableItem <span style="color:Blue; As WbemScripting.SWbemObjectSet
<span style="color:Blue; Dim objRefresher <span style="color:Blue; As <span style="color:Blue; New WbemScripting.SWbemRefresher
<span style="color:Blue; Dim objServicesCimv2_CPU <span style="color:Blue; As WbemScripting.SWbemServicesEx
<span style="color:Blue; Dim objProcess <span style="color:Blue; As WbemScripting.SWbemObjectEx

<span style="color:Blue; Try

<span style="color:Green; //GIVE OURSELVES A BREAK...
Threading.Thread.Sleep(100)

objServicesCimv2_CPU = GetObject(<span style="color:#A31515; "winmgmts:\" & Hostname & <span style="color:#A31515; "rootcimv2")
objRefreshableItem = objRefresher.AddEnum(objServicesCimv2_CPU, <span style="color:#A31515; "Win32_PerfFormattedData_PerfProc_Process").ObjectSet

<span style="color:Green; //CHECK TO SEE IF WE SHOULD EXIT
<span style="color:Blue; If DateTime.Now > StopTime <span style="color:Blue; Then
<span style="color:Green; //EXIT OUR WHILE
<span style="color:Blue; Exit <span style="color:Blue; Do
<span style="color:Blue; End <span style="color:Blue; If

<span style="color:Green; //REFRESH
objRefresher.Refresh()

<span style="color:Green; //GIVE OURSELF CHANGE TO REFRSH...
Threading.Thread.Sleep(100)

WriteRealtimeCPUToDB(Hostname, 0, <span style="color:#A31515; "_Total", <span style="color:#A31515; "_Total", CurrentCPUUsage, 0)

<span style="color:Blue; For <span style="color:Blue; Each objProcess <span style="color:Blue; In objRefreshableItem

<span style="color:Green; //CHECK TO SEE IF WE SHOULD EXIT
<span style="color:Blue; If DateTime.Now > StopTime <span style="color:Blue; Then
<span style="color:Green; //EXIT OUR WHILE
<span style="color:Blue; Exit <span style="color:Blue; Do
<span style="color:Blue; End <span style="color:Blue; If

<span style="color:Green; //RESET OUR VARIABLES
intProcessIDPre = 0
intProcessorUsage = 0
strProcessName = <span style="color:#A31515; ""

<span style="color:Blue; If <span style="color:Blue; Not objProcess <span style="color:Blue; Is <span style="color:Blue; Nothing <span style="color:Blue; Then

<span style="color:Green; //SET VARS
<span style="color:Blue; If objProcess.PercentProcessorTime <span style="color:Blue; Is DBNull.Value <span style="color:Blue; Or objProcess.PercentProcessorTime <span style="color:Blue; Is <span style="color:Blue; Nothing <span style="color:Blue; Then
<span style="color:Green; //SET TO 0
<span style="color:Blue; GoTo NextProcess
<span style="color:Blue; Else
<span style="color:Green; //SET TO VALUE
intProcessorUsage = objProcess.PercentProcessorTime
<span style="color:Blue; End <span style="color:Blue; If

<span style="color:Blue; If intProcessorUsage > 1 <span style="color:Blue; And intProcessorUsage < 100 <span style="color:Blue; And objProcess.Name <> <span style="color:#A31515; "Idle" <span style="color:Blue; And objProcess.Name <> <span style="color:#A31515; "wmiprvse" <span style="color:Blue; And objProcess.Name <> <span style="color:#A31515; "cscript" <span style="color:Blue; And objProcess.IDProcess > 0 <span style="color:Blue; Then
<span style="color:Green; //SET VARS
intProcessIDPre = objProcess.IDProcess
strProcessName = objProcess.Name

<span style="color:Green; //WE KNOW NOTHING ABOUT THE PROCESS, THEREFORE IT IS NEW AND WE ADD IT TO THE LISTVIEW
strUserName = <span style="color:#A31515; "UNKNOWN"

<span style="color:Blue; If objProcess.PrivateBytes <span style="color:Blue; Is DBNull.Value <span style="color:Blue; Or objProcess.PrivateBytes <span style="color:Blue; Is <span style="color:Blue; Nothing <span style="color:Blue; Then
<span style="color:Green; //SET TO 0
intPrivateBytes = 0
<span style="color:Blue; Else
<span style="color:Green; //SET TO VALUE
intPrivateBytes = objProcess.PrivateBytes
<span style="color:Blue; End <span style="color:Blue; If

WriteRealtimeCPUToDB(Hostname, objProcess.IDProcess, objProcess.Name & <span style="color:#A31515; ".exe", strUserName, objProcess.PercentProcessorTime / NumberOfProcessors, intPrivateBytes)

<span style="color:Blue; End <span style="color:Blue; If

<span style="color:Blue; End <span style="color:Blue; If

<span style="color:Green; //LINE LABEL TO SKIP
NextProcess:

<span style="color:Blue; Next

objRefresher.DeleteAll()
objRefreshableItem = <span style="color:Blue; Nothing

<span style="color:Blue; Catch ex <span style="color:Blue; As Exception

<span style="color:Blue; Using AppLog <span style="color:Blue; As <span style="color:Blue; New System.Diagnostics.EventLog

AppLog.Log = <span style="color:#A31515; "Application"
AppLog.Source = <span style="color:#A31515; "ApplicationName"
AppLog.MachineName = <span style="color:#A31515; "."

AppLog.WriteEntry(<span style="color:#A31515; "Error getting RealTime Processes (Inner Loop) for Host (" & Hostname & <span style="color:#A31515; ", Error: " & Err.Description & <span style="color:#A31515; " " & Err.Source & <span style="color:#A31515; ", " & _
ex.Message & <span style="color:#A31515; ", " & ex.StackTrace & <span style="color:#A31515; " ( " & Err.Number & <span style="color:#A31515; "))", EventLogEntryType.<span style="color:Blue; Error)

<span style="color:Blue; End <span style="color:Blue; Using

<span style="color:Blue; Finally

<span style="color:Green; //DESTROY OUR OBJECTS
intProcessIDPre = <span style="color:Blue; Nothing
intProcessorUsage = <span style="color:Blue; Nothing
strProcessName = <span style="color:Blue; Nothing
strUserName = <span style="color:Blue; Nothing
intPrivateBytes = <span style="color:Blue; Nothing
objRefreshableItem = <span style="color:Blue; Nothing
objRefresher.DeleteAll()
objRefresher = <span style="color:Blue; Nothing
objServicesCimv2_CPU = <span style="color:Blue; Nothing
objProcess = <span style="color:Blue; Nothing
<span style="color:Blue; End <span style="color:Blue; Try

<span style="color:Blue; Loop

<span style="color:Blue; Catch Ex <span style="color:Blue; As Exception
<span style="color:Blue; Using AppLog <span style="color:Blue; As <span style="color:Blue; New System.Diagnostics.EventLog

AppLog.Log = <span style="color:#A31515; "Application"
AppLog.Source = <span style="color:#A31515; "ApplicationName"
AppLog.MachineName = <span style="color:#A31515; "."

AppLog.WriteEntry(<span style="color:#A31515; "Error getting RealTime Processes for Host (" & Hostname & <span style="color:#A31515; ", Error: " & Err.Description & <span style="color:#A31515; " " & Err.Source & <span style="color:#A31515; ", " & _
Ex.Message & <span style="color:#A31515; ", " & Ex.StackTrace & <span style="color:#A31515; " ( " & Err.Number & <span style="color:#A31515; "))", EventLogEntryType.<span style="color:Blue; Error)

<span style="color:Blue; End <span style="color:Blue; Using

<span style="color:Blue; Finally
MonitoringProcesses = <span style="color:Blue; False
<span style="color:Blue; End <span style="color:Blue; Try
[/code]

The Function to get Current CPU Usage:

<div style="color:Black;background-color:White; <pre>
<span style="color:Blue; Public <span style="color:Blue; Function CurrentCPUUsage() <span style="color:Blue; As <span style="color:Blue; Integer

<span style="color:Blue; Try

<span style="color:Blue; Using targetCounterObject <span style="color:Blue; As <span style="color:Blue; New PerformanceCounter

<span style="color:Green; //GET CURRENT CPU USAGE
<span style="color:Blue; With targetCounterObject
.MachineName = Hostname
.CategoryName = <span style="color:#A31515; "Processor"
.CounterName = <span style="color:#A31515; "% Processor Time"
.InstanceName = <span style="color:#A31515; "_Total"
.NextValue()
Threading.Thread.Sleep(500)
CurrentCPUUsage = .NextValue
<span style="color:Blue; End <span style="color:Blue; With

<span style="color:Blue; End <span style="color:Blue; Using

<span style="color:Blue; Catch ex <span style="color:Blue; As Exception
<span style="color:Green; //SET ERROR TEXT
lastError = Err.Description

<span style="color:Green; //THROW OUR ERROR
<span style="color:Blue; Throw <span style="color:Blue; New ApplicationException(<span style="color:#A31515; "Error Getting Total CPU Usage: " & lastError)
<span style="color:Blue; End <span style="color:Blue; Try

<span style="color:Blue; End <span style="color:Blue; Function
[/code]

The sub to Write to the Database:

<div style="color:Black;background-color:White; <pre>
<span style="color:Blue; Public <span style="color:Blue; Sub WriteRealtimeCPUToDB(<span style="color:Blue; ByVal strServerName <span style="color:Blue; As <span style="color:Blue; String, <span style="color:Blue; ByVal intPID <span style="color:Blue; As <span style="color:Blue; Integer, <span style="color:Blue; ByVal strImage <span style="color:Blue; As <span style="color:Blue; String, <span style="color:Blue; ByVal strUserName <span style="color:Blue; As <span style="color:Blue; String, <span style="color:Blue; ByVal intPercentUsage <span style="color:Blue; As <span style="color:Blue; Integer, <span style="color:Blue; ByVal intPrivateBytes <span style="color:Blue; As <span style="color:Blue; Integer)
<span style="color:Blue; Try
<span style="color:Green; //WRITES LIVE CPU STATS TO DATABASE
<span style="color:Blue; Using SQLCmd <span style="color:Blue; As <span style="color:Blue; New SqlClient.SqlCommand

<span style="color:Green; CREATE OUR STORED COMMAND
SQLCmd.CommandText = <span style="color:#A31515; "CREATTARGETPROCESS"
SQLCmd.CommandType = CommandType.StoredProcedure
SQLCmd.Connection = DBConnection

SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "strServerName", strServerName)
SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "PID", intPID)
SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "Image", strImage)
SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "PercentUsage", intPercentUsage)
SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "UserName", strUserName)
SQLCmd.Parameters.AddWithValue(<span style="color:#A31515; "PrivateBytes", intPrivateBytes)

SQLCmd.ExecuteNonQuery()

<span style="color:Blue; End <span style="color:Blue; Using

<span style="color:Blue; Catch ex <span style="color:Blue; As Exception
<span style="color:Green; //THROW OUR ERROR
<span style="color:Blue; Throw <span style="color:Blue; New ApplicationException(<span style="color:#A31515; "Error writing Process info to Database for Host: " & Hostname & <span style="color:#A31515; ", Error: " & Err.Description)
<span style="color:Blue; End <span style="color:Blue; Try
[/code]

Would anyone be able to take a look at the above and give me any pointers? Appologies if I have included too much information, didnt want to leave anything important missing :)
Ive read a few threads about a "Microsoft Bug" where a SWbemRefresher object leaks memory when its in a "tight loop" but there doesnt seem to be any facts I can pin, i.e no knowledge base article (other than the WMI process and I think the Win32_Services
class, which wasnt relevant)
Many thanks!


View the full article
 
Back
Top