michaelslamet Posted July 20, 2013 Share Posted July 20, 2013 I tried adding this after the For/Next loop for "; Get PerfProc data" in the original: ; Get PerfProc data For $oProc In $colProcs ; ... Next ; Release Refresher object $oRefresher.DeleteAll $oRefresher = 0 $colProcs = 0 Still had the memory leak. I moved the creation of $oWMI to a Global variable where it is only created once - and there was still a memory leak. Then I moved the creation of $oRefresher outside the loop to a Global - the leak went away. This does not show the memory leak: expandcollapse popup#include <Array.au3>; Only for _ArrayDisplay() ; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process ; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros Global $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & @ComputerName & "\root\cimv2") Global $oRefresher = ObjCreate("WbemScripting.SWbemRefresher") Global $colRefProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet $oRefresher.Refresh HotKeySet("{ESC}", "_Quit") ; Loop to watch for memory leak While 1 _ProcessListProperties() Sleep(20) WEnd Func _Quit() Exit EndFunc ;==>_Quit ;=============================================================================== ; Function Name: _ProcessListProperties() ; Description: Get various properties of a process, or all processes ; Call With: _ProcessListProperties( [$Process [, $sComputer]] ) ; Parameter(s): (optional) $Process - PID or name of a process, default is "" (all) ; (optional) $sComputer - remote computer to get list from, default is local ; Requirement(s): AutoIt v3.2.4.9+ ; Return Value(s): On Success - Returns a 2D array of processes, as in ProcessList() ; with additional columns added: ; [0][0] - Number of processes listed (can be 0 if no matches found) ; [1][0] - 1st process name ; [1][1] - 1st process PID ; [1][2] - 1st process Parent PID ; [1][3] - 1st process owner ; [1][4] - 1st process priority (0 = low, 31 = high) ; [1][5] - 1st process executable path ; [1][6] - 1st process CPU usage ; [1][7] - 1st process memory usage ; [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23) ; [1][9] - 1st process command line string ; ... ; [n][0] thru [n][9] - last process properties ; On Failure: Returns array with [0][0] = 0 and sets @Error to non-zero (see code below) ; Author(s): PsaltyDS at http://www.autoitscript.com/forum ; Date/Version: 07/02/2008 -- v2.0.2 ; Notes: If an integer PID or string process name is provided and no match is found, ; then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList) ; This function requires admin permissions to the target computer. ; All properties come from the Win32_Process class in WMI. ; To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used. ;=============================================================================== Func _ProcessListProperties($Process = "", $sComputer = ".") Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate Local $avProcs[1][2] = [[0, ""]], $n = 1 ; Convert PID if passed as string If StringIsInt($Process) Then $Process = Int($Process) ; Connect to WMI and get process objects ; $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & "\root\cimv2") If IsObj($oWMI) Then ; Get collection processes from Win32_Process If $Process = "" Then ; Get all $colProcs = $oWMI.ExecQuery("select * from win32_process") ElseIf IsInt($Process) Then ; Get by PID $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process) Else ; Get by Name $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'") EndIf If IsObj($colProcs) Then ; Return for no matches If $colProcs.count = 0 Then Return $avProcs ; Size the array ReDim $avProcs[$colProcs.count + 1][10] $avProcs[0][0] = UBound($avProcs) - 1 ; For each process... For $oProc In $colProcs ; [n][0] = Process name $avProcs[$n][0] = $oProc.name ; [n][1] = Process PID $avProcs[$n][1] = $oProc.ProcessId ; [n][2] = Parent PID $avProcs[$n][2] = $oProc.ParentProcessId ; [n][3] = Owner If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName ; [n][4] = Priority $avProcs[$n][4] = $oProc.Priority ; [n][5] = Executable path $avProcs[$n][5] = $oProc.ExecutablePath ; [n][8] = Creation date/time $dtmDate = $oProc.CreationDate If $dtmDate <> "" Then ; Back referencing RegExp pattern from weaponx Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)" $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6") EndIf $avProcs[$n][8] = $dtmDate ; [n][9] = Command line string $avProcs[$n][9] = $oProc.CommandLine ; increment index $n += 1 Next Else SetError(2); Error getting process collection from WMI EndIf ; release the collection object $colProcs = 0 $oRefresher.Refresh ; Get PerfProc data For $oProc In $colRefProcs ; Find it in the array For $n = 1 To $avProcs[0][0] If $avProcs[$n][1] = $oProc.IDProcess Then ; [n][6] = CPU usage $avProcs[$n][6] = $oProc.PercentProcessorTime ; [n][7] = memory usage $avProcs[$n][7] = $oProc.WorkingSet ExitLoop EndIf Next Next Else SetError(1); Error connecting to WMI EndIf ; Return array Return $avProcs EndFunc ;==>_ProcessListProperties So, if you have to repeat the function in a tight loop, this code might help - but it doesn't explain why the $oRefresher Swbemrefresher object leaks so bad in a loop. Is above bold information still valid? Then I moved the creation of $oRefresher outside the loop to a Global - the leak went away Because I put it on the tight loop and face the same problem. If by create the $oRefresher outside the loop to a global solve the problem, I'm going to code it that way Link to comment Share on other sites More sharing options...
michaelslamet Posted July 20, 2013 Share Posted July 20, 2013 Also I found this occasionary cause an error: If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "" & $sUserName If $oProc.GetOwner($sUserName, $sUserDomain) ^ ERROR Since I dont know how to solve it and I dont use that information, I comment that line Link to comment Share on other sites More sharing options...
busysignal Posted July 22, 2013 Share Posted July 22, 2013 Also I found this occasionary cause an error: If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "" & $sUserName If $oProc.GetOwner($sUserName, $sUserDomain) ^ ERROR Since I dont know how to solve it and I dont use that information, I comment that line I did get that same error as you reported but just hung till you pressed ESC. I noticed that it did not output the process list so I some code from the original post and integrated the last posted code change for testing. See if it works for you. expandcollapse popup#include <Array.au3>; Only for _ArrayDisplay() ; Author: PsaltyDS - _ProcessListProperties ; Status: Demo ; Get collection of all processes from Win32_PerfFormattedData_PerfProc_Process ; Have to use an SWbemRefresher to pull the collection, or all Perf data will be zeros Global $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & @ComputerName & "\root\cimv2") Global $oRefresher = ObjCreate("WbemScripting.SWbemRefresher") Global $colRefProcs = $oRefresher.AddEnum($oWMI, "Win32_PerfFormattedData_PerfProc_Process" ).objectSet $oRefresher.Refresh ; Globals - Install a custom error handler - added Global $oMyError = ObjEvent("AutoIt.Error","MyErrFunc"), $f_COMError = False Global $avRET, $iPID HotKeySet("{ESC}", "_Quit") ; Loop to watch for memory leak While 1 _ProcessListProperties() $avRET = _ProcessListProperties() ; added _ArrayDisplay($avRET, "All Processes") ; added Sleep(20) WEnd Func _Quit() Exit EndFunc ;==>_Quit ;=============================================================================== ; Function Name: _ProcessListProperties() ; Description: Get various properties of a process, or all processes ; Call With: _ProcessListProperties( [$Process [, $sComputer]] ) ; Parameter(s): (optional) $Process - PID or name of a process, default is "" (all) ; (optional) $sComputer - remote computer to get list from, default is local ; Requirement(s): AutoIt v3.2.4.9+ ; Return Value(s): On Success - Returns a 2D array of processes, as in ProcessList() ; with additional columns added: ; [0][0] - Number of processes listed (can be 0 if no matches found) ; [1][0] - 1st process name ; [1][1] - 1st process PID ; [1][2] - 1st process Parent PID ; [1][3] - 1st process owner ; [1][4] - 1st process priority (0 = low, 31 = high) ; [1][5] - 1st process executable path ; [1][6] - 1st process CPU usage ; [1][7] - 1st process memory usage ; [1][8] - 1st process creation date/time = "MM/DD/YYY hh:mm:ss" (hh = 00 to 23) ; [1][9] - 1st process command line string ; ... ; [n][0] thru [n][9] - last process properties ; On Failure: Returns array with [0][0] = 0 and sets @Error to non-zero (see code below) ; Author(s): PsaltyDS at http://www.autoitscript.com/forum ; Date/Version: 07/02/2008 -- v2.0.2 ; Notes: If an integer PID or string process name is provided and no match is found, ; then [0][0] = 0 and @error = 0 (not treated as an error, same as ProcessList) ; This function requires admin permissions to the target computer. ; All properties come from the Win32_Process class in WMI. ; To get time-base properties (CPU and Memory usage), a 100ms SWbemRefresher is used. ;=============================================================================== Func _ProcessListProperties($Process = "", $sComputer = ".") Local $sUserName, $sMsg, $sUserDomain, $avProcs, $dtmDate Local $avProcs[1][2] = [[0, ""]], $n = 1 ; Convert PID if passed as string If StringIsInt($Process) Then $Process = Int($Process) ; Connect to WMI and get process objects ; $oWMI = ObjGet("winmgmts:{impersonationLevel=impersonate,authenticationLevel=pktPrivacy}!\\" & $sComputer & "\root\cimv2") If IsObj($oWMI) Then ; Get collection processes from Win32_Process If $Process = "" Then ; Get all $colProcs = $oWMI.ExecQuery("select * from win32_process") ElseIf IsInt($Process) Then ; Get by PID $colProcs = $oWMI.ExecQuery("select * from win32_process where ProcessId = " & $Process) Else ; Get by Name $colProcs = $oWMI.ExecQuery("select * from win32_process where Name = '" & $Process & "'") EndIf If IsObj($colProcs) Then ; Return for no matches If $colProcs.count = 0 Then Return $avProcs ; Size the array ReDim $avProcs[$colProcs.count + 1][10] $avProcs[0][0] = UBound($avProcs) - 1 ; For each process... For $oProc In $colProcs ; [n][0] = Process name $avProcs[$n][0] = $oProc.name ; [n][1] = Process PID $avProcs[$n][1] = $oProc.ProcessId ; [n][2] = Parent PID $avProcs[$n][2] = $oProc.ParentProcessId ; [n][3] = Owner If $oProc.GetOwner($sUserName, $sUserDomain) = 0 Then $avProcs[$n][3] = $sUserDomain & "\" & $sUserName ; [n][4] = Priority $avProcs[$n][4] = $oProc.Priority ; [n][5] = Executable path $avProcs[$n][5] = $oProc.ExecutablePath ; [n][8] = Creation date/time $dtmDate = $oProc.CreationDate If $dtmDate <> "" Then ; Back referencing RegExp pattern from weaponx Local $sRegExpPatt = "\A(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})(?:.*)" $dtmDate = StringRegExpReplace($dtmDate, $sRegExpPatt, "$2/$3/$1 $4:$5:$6") EndIf $avProcs[$n][8] = $dtmDate ; [n][9] = Command line string $avProcs[$n][9] = $oProc.CommandLine ; increment index $n += 1 Next Else SetError(2); Error getting process collection from WMI EndIf ; release the collection object $colProcs = 0 $oRefresher.Refresh ; Get PerfProc data For $oProc In $colRefProcs ; Find it in the array For $n = 1 To $avProcs[0][0] If $avProcs[$n][1] = $oProc.IDProcess Then ; [n][6] = CPU usage $avProcs[$n][6] = $oProc.PercentProcessorTime ; [n][7] = memory usage $avProcs[$n][7] = $oProc.WorkingSet ExitLoop EndIf Next Next Else SetError(1); Error connecting to WMI EndIf ; Return array Return $avProcs EndFunc ;==>_ProcessListProperties Link to comment Share on other sites More sharing options...
francoiste Posted June 20, 2015 Share Posted June 20, 2015 (edited) for some monitoring tasks i'm using WMI with a SWbemRefresher.on most of my system it's working fine. however, i have a few where it fails on the following line:$colItems = $oRefresher.AddEnum($objWMIService, "Win32_PerfFormattedData_PerfProc_Process").ObjectSetany idea how to find out why exactly it's failing?could be system local specific or whatever who knows.any suggestions how to troubleshoot? thanks in advance, francoisteworking code below ...expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Compression=4 #AutoIt3Wrapper_UseUpx=Y #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_Run_Tidy=y #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #pragma compile(ExecLevel, highestAvailable) ;# see http://msdn.microsoft.com/en-us/library/windows/desktop/aa394597%28v=VS.85%29.aspx ("WMI Tasks: Performance Monitoring") Local $strComputer = "." Local $objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2") If @error Or (Not IsObj($objWMIService)) Then MsgBox(4096 + 48, "Error 1", "Error creating wmi object for localhost") Exit 1 EndIf Local $colItems = 0 Local $oRefresher = 0 ;# get collection of all processes from Win32_PerfFormattedData_PerfProc_Process ;# we must use an SWbemRefresher to pull the collection, or all Perf data will be zeros ;# refresher info: http://msdn.microsoft.com/en-us/library/windows/desktop/aa393026%28v=vs.85%29.aspx $oRefresher = ObjCreate("WbemScripting.SWbemRefresher") If @error Or (Not IsObj($oRefresher)) Then MsgBox(4096 + 48, "Error 3a", "error creating wmi refresher object" & @CRLF & @error) Exit 1 EndIf $colItems = $oRefresher.AddEnum($objWMIService, "Win32_PerfFormattedData_PerfProc_Process").ObjectSet If @error Or (Not IsObj($colItems)) Then MsgBox(4096 + 48, "Error 3b", "error adding wmi enum to refresher object" & @CRLF & @error) ;# <--- this is where it fails Exit 1 EndIf $oRefresher.Refresh If (@error == 1) Or (Not IsObj($colItems)) Then MsgBox(4096 + 48, "Error 4a", "error refreshing wmi perfdata object" & @CRLF & @error) Exit 1 Else If ($colItems.count <= 0) Then MsgBox(4096 + 48, "Error 4b", "WMI refresher query did not find the process.") Exit 1 EndIf EndIf ;# time delay before calling the refresher Local $iTime = TimerInit() Do Sleep(50) Until TimerDiff($iTime) > 200 $oRefresher.Refresh MsgBox(4096 + 48, "Done", "Completed successfully.") ;# additional code below ...side note:when i run the original author's code (with custom error handler) it is showing the following error message regarding COM error 80020009: Edited June 20, 2015 by francoiste Link to comment Share on other sites More sharing options...
francoiste Posted July 5, 2015 Share Posted July 5, 2015 (edited) please ignore my previous question on COM error 80020009.i have answered my own question (as to what might be wrong and how to troubleshoot):it turned out that on this particular system my performance counter registry was corrupt!i was also getting errors when running "perfmon.msc".eventually i solved it by following the steps in https://support.microsoft.com/en-us/kb/2554336 :open an elevated command promptCD /D C:\windows\system32lodctr.exe /RCD /D C:\windows\sysWOW64lodctr.exe /RWINMGMT.EXE /RESYNCPERF<reboot> Edited July 7, 2015 by francoiste argumentum and DrLarch 1 1 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now