Диагностика зависания приложения в рабочей программе .NET - PullRequest
4 голосов
/ 14 октября 2008

У меня проблема. Один из пользователей приложения, которое я разрабатываю, время от времени, но регулярно испытывает зависание приложения.

Когда это происходит, мы находим запись с источником «Application Hang» в журнале событий машины с информативным сообщением «Зависание приложения [мое приложение], версия [правильная версия], модуль зависания hangapp, версия 0.0» .0.0, адрес зависания 0x00000000. "

Я регистрирую все необработанные исключения, которые выбрасывает мое приложение, и в моих файлах журналов нет записей, когда это происходит.

Моя текущая рабочая гипотеза состоит в том, что это зависание происходит во время вызова приложения небезопасного устаревшего API. Это не удивило бы меня; Я работал с этим API в течение многих лет, и хотя я не видел, чтобы он зависал раньше, это действительно дрянной код. Также пользователь сообщает, что программа, кажется, зависает в случайное время. Я не думаю, что это действительно так. Не то, чтобы я ей не поверил, а в том, что код, который общается с унаследованным API, работает внутри метода, вызываемого BackgroundWorker. Если бы фоновый поток вызывал зависание приложения, это могло бы очень сильно показаться пользователю случайным.

Итак, у меня есть два вопроса, один конкретный, один общий.

Конкретный вопрос: я ожидаю, что если метод, работающий в потоке, не являющемся пользовательским интерфейсом, зависнет, он просто уничтожит поток. Будет ли это на самом деле убить все приложение?

Общий вопрос:

Я уже регистрирую все необработанные исключения. Моя программа уже настроена на использование трассировки (хотя мне нужно добавить инструментарий для отслеживания активности в подозрительных методах). Есть ли другие вещи, которые я должен делать? Существуют ли диагностические инструменты, позволяющие проводить анализ после сбоя при зависании приложения .NET? Существуют ли в платформе .NET механизмы, которые я могу задействовать для сбора дополнительных (и более полезных) данных?

РЕДАКТИРОВАТЬ: При более внимательном рассмотрении моего кода я вспоминаю, что все его использование BackgroundWorker осуществляется через реализованный мной служебный класс, который оборачивает метод, вызываемый в обработчике исключений. Этот обработчик регистрирует исключение, а затем возвращает его как свойство объекта утилиты. Обработчик события завершения в потоке пользовательского интерфейса перебрасывает исключение (менее чем идеально, поскольку я теряю стек вызовов, но он уже был зарегистрирован), в результате чего основной обработчик исключений пользовательского интерфейса сообщает об исключении в окно сообщения, а затем завершает приложение.

Поскольку ничего этого не происходит, я вполне уверен, что в фоновом потоке нет исключений. Ну, в любом случае, нет .NET исключения.

Дальнейшее наблюдение:

К счастью, я получил достаточно данных от пользователей, чтобы быть уверенным, что зависание не происходит в устаревшем API. Это означает, что я явно что-то не так делаю, а это значит, что я могу это исправить, так что выиграть. Это также означает, что я могу изолировать проблему с помощью отслеживания, что является еще одной победой. Я очень рад ответам, которые я получил на этот вопрос; Я даже счастлив, что мне, вероятно, не нужны они для этой проблемы.

Также: PostSharp выдающийся. Если вам нужно добавить код инструментария в существующее приложение, вы почти наверняка должны его использовать.

Ответы [ 7 ]

4 голосов
/ 14 октября 2008

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

Один из возможных способов диагностировать это - создать дамп процесса, пока он зависает (если предположить, что кто-то рядом заметил, когда это произошло). Это можно сделать с помощью MiniDumpWriteDump из dbghelp.dll. Довольно просто написать простой инструмент, который может создавать дамп процесса (на основе его pid), который может быть предоставлен клиенту, столкнувшемуся с проблемой. Поскольку это управляемое приложение, полный дамп памяти предпочтителен (MiniDumpWithFullMemory), но обычный дамп должен иметь некоторую полезную информацию. Получив дамп, вы можете использовать windbg или выбранный вами посмертный отладчик, чтобы увидеть, что может происходить.

Если вы идете по этому пути, эта статья MSDN является хорошей отправной точкой для отладки управляемого дампа.

1 голос
/ 14 октября 2008

Я бы предложил добавить более подробное ведение журнала вызовов, которые, по вашему мнению, являются источником проблемы.

Если вы работаете в Vista, вы можете использовать новый Vista API, чтобы Windows вызывала ваш код при сбое приложения. Это то, что происходит, когда вы видите, что продукты MS, такие как Office / IE, говорят, что они «пытаются восстановить ваши данные».

0 голосов
/ 15 октября 2008

Я бы предложил подключить WinDbg (да, одна из тех хардкорных вещей) и использовать SOS (Son Of Strike) и SOSEx для анализа тупиков (! Dlk) или вручную проверять блоки синхронизации (! Syncblk), чтобы найти взаимно ожидающие блокировки.

0 голосов
/ 15 октября 2008

Роберт, если все эти решения подведут тебя, и ты все еще думаешь, что унаследованный API является виновником, возможно, ответ заключается в том, чтобы вставить изолированную программную среду унаследованного API в свой собственный домен или процесс.

.NET 3.5 Framework делает это довольно легко, используя API System.AddIn.

0 голосов
/ 14 октября 2008

если возможно, замените фоновый рабочий поток на SafeThread и посмотрите, не перехватит ли это подозрительное исключение. Если это не так, то создаваемое исключение не является исключением CLR, и вы не сможете обработать его из «чистого» кода .NET [SEH из C ++ может работать, хотя]

РЕДАКТИРОВАТЬ: хорошо, это не так. возможно это или это может помочь. Удачи!

0 голосов
/ 14 октября 2008

Если у вас есть необработанное исключение для потока, которым вы управляете, приведет к останову всего вашего приложения . Нет способа "справиться" с этим, как только нить умирает. Возможно, вы захотите узнать, как вы можете использовать APM с делегатами . Это обеспечивает уровень защиты от исключений, создаваемых другими потоками, поскольку исключение захватывается и переносится при вызове EndInvoke ().

Что касается того, что еще вы можете сделать, я второй Чарли ответ.

0 голосов
/ 14 октября 2008

Мысль 1) шаг в код фреймворка .net (из КБ на моей работе):

Если вы установили VS2008 SP1, все, что вам нужно сделать, это перейти в Сервис -> Параметры -> Отладка

  1. Снимите флажок Включить только мой код
  2. Установите флажок Включить пошаговое выполнение .NET Framework
  3. Установите флажок Включить поддержку исходного сервера
  4. В разделе «Отладка -> Символы» добавьте новое местоположение http://referencesource.microsoft.com/symbols

Теперь при отладке чего-либо, у которого в стеке вызовов есть затененный код инфраструктуры, просто щелкните правой кнопкой мыши строку вызова и выберите «Загрузить символы».

Мысль 2) Настройка удаленной отладки http://msdn.microsoft.com/en-us/library/y7f5zaaa.aspx

...