WMIプロセス監視はCPUを使いすぎます!より良い方法はありますか?

StackOverflow https://stackoverflow.com/questions/345199

  •  19-08-2019
  •  | 
  •  

質問

Windowsマシンで特定のプロセスが開始または停止したときを監視する必要があります。現在、WMIシステムにアクセスして5秒ごとにクエリを実行していますが、WMIはWMIであるため、5秒ごとにCPUスパイクが発生します。これを行うより良い方法はありますか?実行中のプロセスのリストを作成し、System.Diagnostics名前空間を介してExitedイベントをアタッチできますが、作成するイベントハンドラはありません。

役に立ちましたか?

解決

これは、現実の世界で正確に行う方法ではありませんが、役立つはずです。これは、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();
    }

他のヒント

WMIイベントをリッスンするときに、終了/クリーンアップ時にイベントから適切にデタッチできなかった場合、CPUスパイクが発生しました。あなたが<!> quot; leaking <!> quot;でないことを確認したいかもしれません。 WMIイベントサブスクリプション。できるだけ早くイベントから切り離し、常にそれを行うようにしてください。

さらに詳しく説明するために、リッスンする私のPowerShellブックの例を次に示します。 PSEventingライブラリを使用してWMIイベントに追加:

  

Add-PSSnapin PSEventing -ErrorAction   SilentlyContinue

     

$ queryString = @ '       選択*       FROM __InstanceModificationEvent       10以内       どこ           TargetInstance ISA 'Win32_Service'           AND TargetInstance.Name = 'w3svc'           AND TargetInstance.State = 'Stopped' '@

     

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

     

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

     

Connect-EventListenerウォッチャー   EventArrived

     

$ watcher.Start()

     

echo <!> quot; W3CSVCサービスを待機しています   停止するには... <!> quot; Get-Event -wait | foreach {           Write-Host -foreground Red <!> quot; W3SVCサービスが停止しました!<!> quot;       }

     

$ watcher.Stop()

     

Disconnect-EventListenerウォッチャーEventArrived

     

echo <!> quot; done <!> quot;

スクリプトの終了時に Disconnect-EventListener ビットを実行しないと、イベントに3回目または4回目にCPUスパイクが発生します。私の推測では、システムはまだイベントを配信しようとしています。

プロセスのPID /名前のみを探している場合は、代わりに<!> quot; SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'などのWQLクエリを使用して、Win32_ProcessTraceイベントを取得できます。 <!> quot; 該当する場合*

<!> quot; SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE TargetInstance ISA 'Win32Process' AND TargetInstance.Name = 'name' <!> quot;を使用する場合の落とし穴バックエンドでの動作にあります。 %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以上が必要であることを示していることに注意してください。古いOSを使用している場合、__ InstanceModificationEventクエリを使用してスタックする可能性があります。

ここでの私の答えは、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>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top