WMI 进程监视使用过多的 CPU! 还有更好的方法吗?
我需要观察 Windows 计算机上某些进程何时启动或停止。 我目前正在使用 WMI 系统并每 5 秒查询一次,但这会导致每 5 秒出现一次 CPU 峰值,因为 WMI 是 WMI。 有更好的方法吗? 我可以创建一个正在运行的进程列表,并通过 System.Diagnostics 命名空间将 Exited 事件附加到它们,但没有用于创建的事件处理程序。
I need to watch when certain processes are started or stopped on a Windows machine. I'm currently tapped into the WMI system and querying it every 5 seconds, but this causes a CPU spike every 5 seconds because WMI is WMI. Is there a better way of doing this? I could just make a list of running processes and attach an Exited event to them through the System.Diagnostics Namespace, but there is no Event Handler for creation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这并不完全是您在现实世界中的做法,但应该会有所帮助。 这似乎对我的 CPU 没有太大的推动作用。
This is not exactly how you'd do it in the real world but should help. This seems not to drive my CPU much at all.
我在这里的回答提到了 WMI 以外的替代方案:https://stackoverflow.com/a/50315772/3721646
如果设计不当,WMI 查询可能会消耗大量 CPU 性能。 如果使用 Win32_Process 类的内部事件来跟踪进程创建事件,则会严重影响性能。 另一种方法是利用安全审核日志。 您可以使用本地安全策略启用进程跟踪,或者在多台计算机的情况下使用 GPO。 进程跟踪开始后,您可以使用自定义 XML 查询订阅安全事件日志,以监控您感兴趣的某些进程。 进程创建事件 ID 为 4688。`
My answer here mentions an alternative other than WMI:https://stackoverflow.com/a/50315772/3721646
WMI queries can cost heavy CPU performance if not designed properly. If an intrinsic event from Win32_Process class is used to track process creation event, this impacts performance heavily. An alternate approach is to leverage Security Audit logs. You can enable Process Tracking using Local Security Policy or using a GPO in case of multiple machines. Once the process tracking starts, you can subscribe to security event logs with a custom XML query to monitor certain processes of your interest. The process creation event ID is 4688. `
如果您只想查找进程的 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):
如您所见,远程计算机上的实际事件实现是针对 Win32_Process 执行查询在由WITHIN 子句中的值指定的间隔上。 因此,在该轮询中启动和停止的任何进程都不会触发事件。
您可以将WITHIN子句设置为一个较小的值,以尽量减少这种影响,但更好的解决方案是使用像Win32_ProcessTrace这样的真实事件,它应该始终触发。
*请注意,MSDN 表明 Win32_ProcessTrace 至少需要客户端计算机上的 Windows XP 和服务器计算机上的 Windows 2003 才能工作。 如果您使用的是较旧的操作系统,则可能会因使用 __InstanceModificationEvent 查询而陷入困境。
If you are only looking for PID/Name of your processes, you may instead wish to pick up on Win32_ProcessTrace events, using a WQL query such as "SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'" if applicable*.
The pitfall of using "SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name'" is in how it works on the back end. If you inspect wbemess.log within your %windir%\system32\wbem\logs directory, you will notice the following logs (using __InstanceDeletionEvent):
As you can see, the actual event implementation on the remote machine is to perform a query against Win32_Process on an interval that is specified by your value in the WITHIN clause. As a result, any processes that start and stop within that poll will never fire an event.
You can set the WITHIN clause to a small value to try and minimize this effect, but the better solution is to use a true event like Win32_ProcessTrace, which should always fire.
*Note that MSDN indicates Win32_ProcessTrace requires a minimum of Windows XP on a client machine and Windows 2003 on a server machine to work. If you are working with an older OS, you may be stuck using the __InstanceModificationEvent query.
在侦听 WMI 事件时,如果我未能在退出/清理时正确地从事件中分离,我会遇到 CPU 峰值。 您可能需要检查是否“泄漏”了 WMI 事件订阅。 以防万一,尽早脱离活动,并确保你始终这样做。
为了进一步说明,这里有一个来自 我的 PowerShell 书籍 的示例,该示例侦听 WMI 事件使用 PSEventing 库:
如果我在脚本退出时不执行 Disconnect-EventListener 位,我会在第三次或第四次附加到事件。 我的猜测是系统仍在尝试传递事件。
I've had CPU spikes when listening to WMI events in cases where I have failed to detach properly from my events on exit/cleanup. You might want to check you are not "leaking" WMI event subscriptions. Just in case detach from the event as early as possible and make sure you always do it.
To illustrate further, here's an example from my PowerShell book that listens to WMI events using the PSEventing library:
If I do not do the Disconnect-EventListener bit upon script exit, I get CPU spikes the third or fourth time I attach to the event. My guess is that the system still tries to deliver events.