Дело о мееееедленной системе
Несколько недель назад моя жена пожаловалась мне, что Vista на ее настольном компьютере не реагирует на движение мышкой или ввод с клавиатуры. Принимая во внимание важность этого клиента, я тут же сел за компьютер, чтобы решить эту проблему. Система, как выяснилось, зависла не полностью, но ужасно тормозила. Например, когда я переместил курсор мыши на кнопку Start и нажал ее, то меню раскрылось секунд через тридцать. Я подумал, что что-то загружает процессор и эту проблему можно решить простым завершением сеанса или перезагрузкой, но я точно знал, что если я не выявлю причину столь низкой производительности и не решу ее, то, скорее всего, в ближайшем будущем моей жене вновь понадобится моя техническая помощь. В любом случае сдаваться на милость такой проблемы находится ниже моего достоинства. И поэтому я решил начать новое расследование.
Первое, что я сделал - это запустил Process Explorer, чтобы понять, какой процесс нещадно потреблял все ресурсы процессора. Через несколько минут томительного ожидания Process Explorer запустился и показал, что не один, а даже несколько процессов и потребляли все мощности процессора, каждый по 50%: iexplore.exe и dllhost.exe. Iexplore, как вы, наверное, догадались, это Internet Explorer (IE). Но я предположил, что причиной проблемы, скорее всего, является не сам IE, а один из BHO-объектов (абб. от browser helper object), элемент управления ActiveX или какой-нибудь плагин, загруженный в IE. Dllhost.exe является корневым процессом для COM сервера DLL-библиотек, так что проблема явно была не в самом процессе, а в COM-сервере, загруженном в процесс. Оба варианта требовали дальнейших изысканий.
Начать я решил с IE. В попытке высвободить немного вычислительной мощи, в рамках которой я бы смог действовать, я приостановил процесс Dllhost, кликнув по нему правой кнопкой в Process Explorer и выбрав в контекстном меню опцию Suspend:
Это действие перевело статус процесса Dllhost в состояние сна и, как я и ожидал, высвободило порядка 50% процессорного времени. Это произошло потому, что компьютер построен на базе двухъядерного процессора, и для потребления всех 100% процессорных циклов процесс должен иметь два потока, чтобы каждый поток загружал по одному ядру. Большинство ошибок, грузящих процессор, с которыми я встречался в реальной жизни, были однопотоковыми.
Не процессы исполняют код - его исполняют потоки, поэтому мне надо было заглянуть внутрь процесса IE, чтобы увидеть какой поток или потоки запущены. Поэтому дважды щелкнув на процессе Iexplore.exe в Process Explorer, я переключился на вкладку Threads. Было запущено несколько потоков, но один доминировал в потреблении ресурсов процессора.
Из своего опыта я знаю, что Ieframe.dll является частью IE, но чтобы в этом убедиться, на закладке Threads я нажал кнопку Modules и перешел на вкладку Details.
Так как описание не помогло в определении предназначения потока, я решил обратиться к еще одной подсказке - функции запуска. Так как мой Process Explorer настроен на получение символов для образов Windows из сервера символов Microsoft, то Process Explorer сразу же показывал мне название функции, с которой начиналось исполнение потока. Иногда DLL или функции, с которой начинается поток, достаточно, чтобы понять назначение потока, ставшего причиной проблемы. В данном случае поток начинался с функции CTablWindow::_TabWindowThreadProc. Эта функция запускает основной поток вкладок, но причина, почему этот поток потреблял столько ресурсов, осталась загадкой. Нужно было копнуть еще глубже и проверить, куда именно исполняется поток.
Чтобы узнать, что именно делает поток, я два раза щелкнул на списке потоков, чтобы открыть диалоговое окно стека потока, которое показывает функции в стеке потока. По сути, стек - это история запуска функций, в которой каждая указанная функция вызвана функцией, находящейся выше по списку, а самая первая в списке функция, была выполена потоком как раз перед тем как Process Explorer подключился к стеку. Я пролистал список, чтобы найти строки, которые бы указывали на обращение к сторонним DLL или плагинам IE, так как вероятность того, что ошибка была именно в них намного больше, чем если бы она была в самом IE. Действительно, я нашел ссылки, указывающие на популярный элемент управления ActiveX - Adobe Flash:
Для того, чтобы быть уверенным, что я не ошибся, и именно Flash, а не какой-то другой компонент потребляет большую часть времени процессора, я закрыл и открыл окно подключения к стеку несколько раз, но оно все время указывало на Flash.
Первое, что я делаю, когда подозреваю, что какое-либо ПО вызывает проблему, это проверяю сайт производителя, чтобы убедится, что у меня последняя версия ПО. Я открыл режим просмотра DLL в Process Explorer и посмотрел версию Flash.ocx, потом я перешел на сайт Adobe, посмотрел на последнюю версию Flash. Они совпадали.
Я был в тупике. Я не мог понять, где кроется ошибка - в самом Flash или, что более вероятно, в Flash-приложении. Также не было никакой уверенности в том, что проблема снова себя проявит. Я пытался определить, на каком сайте присутствует Flash-контент, закрывая вкладки одну за одной, но даже когда я закрыл их все, поток все равно работал.
На данном этапе единственным возможным вариантом было удалить Flash или принудительно завершить процесс IE, чтобы избавится от чудовищной загрузки процессора, и надеяться, что больше это не повторится. Я выбрал последний вариант и дело осталось открытым. С тех пор, как я проводил это расследование, я сталкивался с подобным поведением Flash как на своем компьютере, так и на компьютере жены, поэтому я неусыпно следил за сайтом Adobe на наличие обновлений. Я был разочарован тем, что не получил никакого фактического результата, но, по крайней мере, я знал, что вызывало загрузку процессора.
Теперь я вернулся к проблеме Dllhost в надежде, что здесь мне удастся найти решение проблемы. В всплывающем окне Process Explorer показывает компонент или компоненты, загруженные в корневые процессы Svchost.exe (обслуживающий корневой процесс Windows), Rundll32 (корневой процесс аплетов панели управления), Taskeng.exe (корневой процесспланировщика заданий в Vista и Server 2008) и Dllhost.exe. Я навел мышку на Dllhost.exe, чтобы увидеть, какой COM-сервер запущен в рамках процесса.
Это был COM-сервер Thumbnail Cache, отвечающий за создание в Windows Explorer эскизов изображений и видео-файлов. Он является частью Windows, так что мне еще раз пришлось лезть внутрь процесса за дополнительными подробностями. Я снова запустил процесс Dllhost, который я приостановил ранее, и открыл страницу свойств потоков процесса.
В данном случае все мощности процессора потребляла функция ObjectThread из Quartz.dll. Я заглянул в ее свойства, и увидел, что это еще одна библиотека Windows, компонент DirectShow Runtime со стандартным именем функции:
Я снова дважды щелкнул на имени процесса, чтобы увидеть стек потока.
Первые несколько строчек содержали информацию о User32.dll и Ntdll.dll, основных системных библиотеках Windows, но в строчках 4-7 содержалась информация о стороннем компоненте Sonicmp4demux.ax (.ax - расширение, часто используемое фильтрами для DirectShow). Имена функций в этих библиотеках были те же самые, что не имело никакого смысла, так как сервер символов Microsoft хранит символы только для ПО, поставляемого с Windows. Еще несколько снимков состояния стека подтвердили, что это был именно тот код, который вызывал столь серьезное потребление ресурсов.
Теперь, когда у меня была гипотеза, следующим моим шагом было проверить существование новой версии. Но сначала мне было необходимо узнать, с каким ПО поставляется данная библиотека, что было сложнее, чем кажется на первый взгляд. Я открыл режим просмотра библиотек, чтобы ближе взглянуть на информацию о версии, но описание не дало какой-либо полезной информации.
Ни в меню Start, ни в списке установленных приложений не было ничего похожего на Sonic. Я искал в Windows Live по запросу "Sonic" и узнал, что это часть программного пакета для работы с DC и DVD от Roxio. Я поискал в меню Start и, конечно же, нашел папку Roxio.
Я запустил приложение от Roxio, чтобы узнать номер версии, и обнаружил, что приложение Creator имеет встроенную возможность по проверке обновлений. Я запустил его, но обновлений не получил.
На всякий случай я зашел на сайт Roxio и оказалось, что таки есть новая версия, которую встроенный загрузчик не предлагал просто потому, что обновление, согласно описанию, не предлагало ничего нового.
Я все равно его загрузил (все 640 Мб!) и ждал около 15 минут, пока пакет установится. Потом я проверил информацию о версии Sonicmp4demux.ax, но номер версии - 1.4.402.60802 - был идентичен тому, который я видел в режиме просмотра библиотек, а сам файл был двухлетней давности.
Я мог бы удалить программный пакет и проблема более никогда бы не появилась, но мне не хотелось расставаться с возможностью создавать DVD с помощью Roxio. Для меня не являлось трагедией, если я больше не буду видеть специальные значки файлов форматов образов, связанных с Roxio, я даже не был уверен, что видел когда-либо таковой в Windows Explorer, поэтому я решил выключить только демультиплексор от Sonic. Я мог провести поиск в реестре по имени библиотеки, где она, конечно же, была зарегистрирована, но это грубый подход, и в случае существования непрямых или дублирующихся ссылок я мог легко дойти до того, что перестало бы работать не только создание эскизов изображений, но повредилось бы что-то более серьезное.
Process Monitor - лучше всего подходит для подобной работы. Так как я не знал, когда именно проблема появится снова, на ее повторение могли уйти дни, я не хотел просто запустить программу и отдать ей на съедение всю виртуальную память, так что я ограничил глубину хранения истории в Process Monitor 1 миллионом событий.
Также я включил фильтр на поиск совпадений с адресом C:\Windows\System32\Dllhost.exe, свернул программу и пустил жену за компьютер.
На следующий день, когда я вернулся с работы и сел за компьютер, я увидел, что процесс Dllhost.exe снова потребляет около 50% времени процессора. Я предположил, что так как система двухъядерная, то эта проблема появлялась регулярно, однако, моя жена этого не замечала, так как оставшихся ресурсов было достаточно, для нормальной работы (еще одна хорошая причина покупать многоядерные процессоры!). В Process Monitor за это время было записано около 114000 операций с Dllhost, что было явно слишком много, чтобы изучить их все индивидуально. Я запустил поиск sonicmp4 и ближе к концу трассировки нашел ссылку на запрос к реестру.
Система запрашивала зарегистрированый COM-объект мультиплексора. Так как COM-объект является сторонней библиотекой, то я был уверен, что COM Class ID (CLSID) не жестко прописан в Windows, так что я вернулся к началу трассировки и начал искать значение A7DD215 (первые несколько знаков данного CLSID). Поиск нашел совпадение на несколько тысяч операций раньше.
CLSID содержался в имени ключа реестра в еще одном регистраторе COM-объекта. Я провел поиск в Windows Live родительского CLSID и обнаружил эту статью в базе знаний Microsoft, в которой объяснено, в каком ключе реестра зарегистрированы фильтры DirectShow. Я взглянул на стек в поисках определенного запроса, чтобы убедится в том, что Dllhost читает данные именно оттуда.
Теперь я был уверен, что могу просто переименовать ключ регистрации фильтра Sonic, чтобы предотвратить его использование. Я никогда не удаляю ключи реестра, когда провожу такого рода диагностику, просто на случай, если изменение заблокирует важную функциональность или каким-то образом нанесет вред системе. Из трассировок я понял, что генератор кэша эскизов нашел AVI файл, который вынудил генератор кэша загрузить демультиплексор от Sonic, этот формат Windows явно может обработать и сама, так что я был уверен, что все продолжит работать нормально. После завершения процесса Dllhost и внесения изменений, я открыл ту же папку, удалил эскизы и убедился, что насколько я могу судить, уменьшения функциональности не произошло. После чего я успешно воспользовался Roxio для записи DVD с множеством AVI-файлов. Дело было закрыто.
Системой моей жены снова можно было пользоваться и хотя я не смог раскрыть причин столь серьезной загрузки процессора Flash-плагином, я, по крайней мере, знал причину, поэтому мог следить за обновлениями. Что более важно, решив часть дела по Dllhost, даже если Flash опять начнет сходить с ума, я сделал систему снова годной к использованию. Теперь моя жена более не будет сталкиваться с такими инцидентами. В очередной раз спасибо Process Explorer и Process Monitor.