WMI Process Watching использует слишком много процессора! Любой лучший метод? - PullRequest
2 голосов
/ 06 декабря 2008

Мне нужно наблюдать, когда определенные процессы запускаются или останавливаются на машине с Windows. В настоящее время я подключаюсь к системе WMI и запрашиваю ее каждые 5 секунд, но это вызывает скачок ЦП каждые 5 секунд, потому что WMI - это WMI. Есть ли лучший способ сделать это? Я мог бы просто составить список запущенных процессов и прикрепить к ним событие Exited через пространство имен System.Diagnostics, но для создания нет обработчика событий.

Ответы [ 4 ]

1 голос
/ 06 декабря 2008

У меня были пики ЦП при прослушивании событий WMI в тех случаях, когда я не смог правильно отсоединиться от своих событий при выходе / очистке. Возможно, вы захотите убедиться, что вы не «пропускаете» подписки на события WMI. На всякий случай отсоединитесь от мероприятия как можно раньше и убедитесь, что вы всегда это делаете.

Чтобы проиллюстрировать это, вот пример из моей книги PowerShell , которая прослушивает события WMI с использованием библиотеки PSEventing:

Add-PSSnapin PSEventing -ErrorAction SilentlyContinue

$ queryString = @ ' ВЫБРАТЬ * ОТ __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 ($ запроса)

Connect-EventListener watcher EventArrived

$ watcher.Start ()

echo "Ожидание услуги W3CSVC остановить ... "Get-Event-Wait | foreach { Write-Host -foreground Red "Служба W3SVC остановлена!" } * * Тысяча двадцать-один

$ watcher.Stop ()

Disconnect-EventListener наблюдатель EventArrived

эхо "сделано"

Если я не выполняю бит Disconnect-EventListener при выходе из скрипта, я получаю пики ЦП в третий или четвертый раз, когда присоединяюсь к событию. Я предполагаю, что система все еще пытается доставить события.

1 голос
/ 23 июля 2009

Если вы ищете только PID / Имя ваших процессов, вы можете вместо этого выбрать события Win32_ProcessTrace, используя WQL-запрос, такой как «SELECT * FROM Win32_ProcessTrace WHERE TargetInstance.ProcessName = 'name'" если применимо *.

Подводный камень использования «SELECT * FROM __InstanceModificationEvent В ТЕЧЕНИИ 10 ГДЕ TargetInstance ISA« Win32Process »И TargetInstance.Name = 'name'» заключается в том, как он работает на серверной части. Если вы проверите wbemess.log в вашем каталоге% windir% \ system32 \ wbem \ logs, вы заметите следующие журналы (используя __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

Как вы можете видеть, фактическая реализация события на удаленной машине заключается в выполнении запроса к Win32_Process с интервалом, который указан вашим значением в предложении WITHIN. В результате любые процессы, которые запускаются и останавливаются в этом опросе, никогда не будут вызывать событие.

Вы можете установить для предложения WITHIN небольшое значение, чтобы попытаться минимизировать этот эффект, но лучшим решением будет использование истинного события, такого как Win32_ProcessTrace, которое должно всегда срабатывать.

* Обратите внимание, что MSDN указывает, что для работы Win32_ProcessTrace требуется как минимум Windows XP на клиентском компьютере и Windows 2003 на сервере. Если вы работаете с более старой ОС, вы можете застрять с помощью запроса __InstanceModificationEvent.

1 голос
/ 06 декабря 2008

Это не совсем то, как вы бы это делали в реальном мире, но это должно помочь. Кажется, это совсем не сильно влияет на мой процессор.

    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();
    }
0 голосов
/ 13 мая 2018

В моем ответе здесь упоминается альтернатива, отличная от WMI: https://stackoverflow.com/a/50315772/3721646 Запросы WMI могут стоить высокой производительности ЦП, если не спроектированы должным образом. Если для отслеживания события создания процесса используется внутреннее событие из класса Win32_Process, это сильно влияет на производительность. Альтернативный подход заключается в использовании журналов аудита безопасности. Вы можете включить отслеживание процессов с помощью локальной политики безопасности или с помощью объекта групповой политики в случае нескольких компьютеров. После запуска отслеживания процессов вы можете подписаться на журналы событий безопасности с помощью специального XML-запроса, чтобы отслеживать определенные процессы, которые вас интересуют. Идентификатор события создания процесса - 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>
...