WMI进程监视使用太多的CPU!有更好的方法吗?

时间:2008-12-05 21:26:14

标签: c# wmi wmi-query

我需要观察在Windows计算机上启动或停止某些进程的时间。我目前正在进入WMI系统并每隔5秒查询一次,但由于WMI是WMI,因此每隔5秒就会出现一次CPU峰值。有没有更好的方法呢?我可以只列出正在运行的进程并通过System.Diagnostics命名空间将Exited事件附加到它们,但是没有用于创建的事件处理程序。

4 个答案:

答案 0 :(得分:1)

这不完全是你在现实世界中的表现,但应该有所帮助。这似乎根本不会驱动我的CPU。

    static void Main(string[] args)
    {
        // Getting all instances of notepad
        // (this is only done once here so start up some notepad instances first)
        // you may want use GetProcessByPid or GetProcesses and filter them as required
        Process[] processesToWatch = Process.GetProcessesByName("notepad");

        foreach (var process in processesToWatch)
        {
            process.EnableRaisingEvents = true;
            process.Exited +=
                (s, e) => Console.WriteLine("An instance of notepad exited");
        }

        Thread watchThread = new Thread(() =>
            {
                while (true)
                {
                    Process[] processes = Process.GetProcesses();
                    foreach (var process in processes)
                    {
                        Console.WriteLine("{0}:{1}", process.Id, process.ProcessName);
                    }
                    // Don't dedicate a thread to this like I'm doing here
                    // setup a timer or something similiar
                    Thread.Sleep(2000);
                }
            });
        watchThread.IsBackground = true;
        watchThread.Start();

        Console.WriteLine("Polling processes and waiting for notepad process exit events");
        Console.ReadLine();
    }

答案 1 :(得分:1)

在我退出/清理时无法正确分离事件的情况下,我在收听WMI事件时遇到CPU峰值。您可能想要检查您是否“泄漏”WMI事件订阅。以防万一从事件中脱离,并确保你总是这样做。

为了进一步说明,这里是my PowerShell book使用PSEventing库监听WMI事件的示例:

  

Add-PSSnapin PSEventing -ErrorAction   SilentlyContinue

     

$ queryString = @'       选择 *       FROM __InstanceModificationEvent       在10       哪里           TargetInstance ISA'Win32_Service'           AND TargetInstance.Name ='w3svc'           AND TargetInstance.State ='已停止''@

     

$ query = New-Object System.Management.WQLEventQuery`       -argumentList $ queryString

     

$ watcher = New-Object   System.Management.ManagementEventWatcher($查询)

     

Connect-EventListener观察者   EventArrived

     

$ watcher.Start()

     

echo“等待W3CSVC服务   停止......“Get-Event -wait | foreach {           Write-Host -foreground Red“W3SVC服务已停止!”       }

     

$ watcher.Stop()

     

Disconnect-EventListener观察者EventArrived

     回声“完成”

如果我在脚本退出时没有执行 Disconnect-EventListener 位,我会在第三次或第四次附加到事件时获得CPU峰值。我的猜测是系统仍然试图传递事件。

答案 2 :(得分:1)

如果您只是在寻找进程的PID /名称,您可能希望使用WQL查询来获取Win32_ProcessTrace事件,例如“SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName ='name'”如果适用*

使用“SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA'Win32Process'AND TargetInstance.Name ='name'”的缺陷在于它在后端的工作原理。如果检查%windir%\ system32 \ wbem \ logs目录中的wbemess.log,您会注意到以下日志(使用__InstanceDeletionEvent):

(Wed Jul 22 13:58:31 2009.73889577) : Registering notification sink with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 047209E0 with query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process' in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 0225E560 with query select * from __ClassOperationEvent where TargetClass isa "Win32_Process" in namespace //./root/CIMV2.
(Wed Jul 22 13:58:31 2009.73889577) : Activating filter 'select * from __ClassOperationEvent where TargetClass isa "Win32_Process"' with provider $Core
(Wed Jul 22 13:58:31 2009.73889587) : Activating filter 'select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process'' with provider $Core
(Wed Jul 22 13:58:31 2009.73889587) : Instituting polling query select * from Win32_Process to satisfy event query select * from __InstanceDeletionEvent within 10 where TargetInstance ISA 'Win32_Process'
(Wed Jul 22 13:58:31 2009.73889587) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2'
(Wed Jul 22 13:58:31 2009.73889697) : Polling query 'select * from Win32_Process' done
(Wed Jul 22 13:58:41 2009.73899702) : Executing polling query 'select * from Win32_Process' in namespace '//./root/CIMV2'
(Wed Jul 22 13:58:41 2009.73899792) : Polling query 'select * from Win32_Process' done

如您所见,远程计算机上的实际事件实现是在由WITHIN子句中的值指定的时间间隔内对Win32_Process执行查询。因此,在该轮询中开始和停止的任何进程都不会触发事件。

您可以将WITHIN子句设置为较小的值以尝试并最小化此效果,但更好的解决方案是使用类似Win32_ProcessTrace的真实事件,该事件应始终触发。

*请注意,MSDN表示Win32_ProcessTrace需要客户端计算机上的最低Windows XP和服务器计算机上的Windows 2003才能工作。如果您使用的是较旧的操作系统,则可能会遇到使用__InstanceModificationEvent查询的问题。

答案 3 :(得分:0)

我在这里的回答提到了除WMI之外的其他选择:https://stackoverflow.com/a/50315772/3721646 如果设计不当,WMI查询可能会导致CPU性能过高。如果使用Win32_Process类中的内部事件来跟踪进程创建事件,则会严重影响性能。另一种方法是利用安全审核日志。您可以使用本地安全策略启用进程跟踪,或者在多台计算机的情况下使用GPO。进程跟踪开始后,您可以使用自定义XML查询订阅安全事件日志,以监控您感兴趣的某些进程。进程创建事件ID为4688.“

<QueryList>
 <Query Id="0" Path="Security">
   <Select Path="Security">
       *[EventData[Data[@Name='NewProcessName'] ='C:\Windows\explorer.exe']]
       and
       *[System[(EventID=4688)]]
   </Select>
 </Query>
</QueryList>