Обработка исключений в профилирующем API
Из всех исключений уведомления об исключениях являются наиболее трудными для понимания и описания. В данном разделе описывается обработка исключений и объясняется обработка профилирующим API различных типов исключений.
Схема уведомления об исключениях
Обработка исключений является сложным процессом. Уведомления об исключениях, описанные в данном разделе, предоставляют всю информацию, требуемую сложному профилировщику для отслеживания передачи (фаза поиска или обратная фаза), фрейма, filter и блока finally, выполняемого для каждого потока в профилированном потоке. Уведомления об исключениях не предоставляют каких-либо ThreadID, однако предусмотрена возможность вызова метода ICorProfilerInfo::GetCurrentThreadID для определения управляемого потока, вызвавшего исключение.
На следующей иллюстрации представлена схема приема профилировщиком кода различных обратных вызовов при мониторинге событий исключения. Каждый поток начинается в нормальном состоянии выполнения. При нахождении потока в состоянии в системе исключений (в фазе поиска или обратной фазе) он управляется системой исключения. Для любых обратных вызовов, не связанных с исключениями (например, ICorProfilerCallback::ObjectAllocated), возникающими при нахождении потока в одном из данных состояния, могут использоваться атрибуты самой системы исключения. При нахождении потока в состоянии вне системы исключения он выполняет произвольный управляемый код.
Последовательность обратного вызова исключений
Вложенные исключения
Пересечение потоками управляемого кода в процессе обработки исключения может вызвать другое исключение, которое может привести к новой передаче обработки исключения. На предыдущей иллюстрации эта передача помечена как "Передача обработки нового исключения". Если такое вложенной исключение обходит блоки filter/finally/catch из исходного исключения, исходное исключение может быть затронуто следующим образом:
При возникновении вложенного исключения в блоке filter и обходе блока filter filter будет определен для возвращения false и первая передача будет продолжена.
При возникновении вложенного исключения в блоке finally и обходе блока finally обработка исходного исключения возобновлена не будет.
При возникновении вложенного исключения в блоке catch и обходе блока catch обработка исходного исключения возобновлена не будет.
Неуправляемые обработчики
Исключение может быть обработано в неуправляемом коде. В этом случае профилировщик увидит обратную фазу, однако не получит уведомления обработчиков catch. Выполнение будет возобновлено в нормальном режиме в неуправляемом коде. Профилировщик, обладающий сведениями о неуправляемом коде, сможет определить эту ситуацию. Профилировщик, поддерживающий только управляемый код, определит любое количество элементов, включая (но не ограничиваясь):
Обратный вызов ICorProfilerCallback::UnmanagedToManagedTransition при вызове управляемым кодом или возвращении в управляемый код.
Завершение потока (если неуправляемый код находился в корне потока).
Завершение приложения (если неуправляемый код завершает приложение).
Обработчики CLR-данных
Исключение может быть обработано непосредственно средой CLR. В этом случае профилировщик увидит обратную фазу, однако не получит уведомления обработчиков catch. Профилировщик может получить данные о нормальном возобновлении управляемого или неуправляемого кода.
Необработанные исключения
По умолчанию необработанное исключение приведет к завершению процесса в платформе .NET Framework версии 2.0. Можно принудительно обеспечить соблюдение политики исключений платформы .NET Framework версии 1.0 посредством использования флага совместимости, как описано в разделе Исключения в управляемых потоках.