Gestion des exceptions dans l'API de profilage
Les notifications d'exception sont les notifications les plus difficiles à décrire et à comprendre. Cette rubrique décrit le traitement des exceptions et explique comment l'API de profilage gère les différents types d'exceptions.
Organigramme des notifications d'exception
Le traitement des exceptions est fondamentalement complexe. Les notifications d'exception décrites dans cette rubrique fournissent à un profileur sophistiqué toutes les informations nécessaires pour assurer le suivi de la phase (phase de recherche ou phase de déroulement), du frame, du bloc filter et du bloc finally qui est exécuté pour chaque thread dans le processus profilé. Les notifications d'exception ne fournissent pas de ThreadID, mais vous pouvez appeler la méthode ICorProfilerInfo::GetCurrentThreadID pour connaître le thread managé qui a levé l'exception.
L'illustration suivante indique comment le profileur de code reçoit différents rappels lorsqu'il surveille des événements d'exception. Chaque thread commence dans l'état d'exécution normale. Lorsque le thread est dans un état à l'intérieur du système d'exceptions (en phase de recherche ou en phase de déroulement), il est contrôlé par le système d'exceptions. Tout rappel non lié à des exceptions (par exemple, ICorProfilerCallback::ObjectAllocated) qui se produit pendant que le thread est dans l'un de ces états peut être attribué au système d'exceptions lui-même. Lorsque le thread est dans un état à l'extérieur du système d'exceptions, il exécute du code managé arbitraire.
Séquence de rappels d'exception
Exceptions imbriquées
Les threads qui sont parvenus dans du code managé pendant le traitement d'une exception pourraient lever une autre exception, ce qui donnerait lieu à une nouvelle phase complète de gestion des exceptions. (Cette nouvelle phase est désignée par « Nouvelle phase de gestion des exceptions » dans l'illustration précédente.) Si une exception imbriquée de ce type échappe aux blocs filter/finally/catch à partir de l'exception d'origine, cela peut influer sur l'exception d'origine de la façon suivante :
Si l'exception imbriquée s'est produite dans un bloc filter et échappe au bloc filter, le filter a pour valeur de retour false et la première phase se poursuit.
Si l'exception imbriquée s'est produite dans un bloc finally et échappe au bloc finally, le traitement de l'exception d'origine est définitivement interrompu.
Si l'exception imbriquée s'est produite dans un bloc catch et échappe au bloc catch, le traitement de l'exception d'origine est définitivement interrompu.
Gestionnaires non managés
Une exception peut être prise en charge dans du code non managé. Dans ce cas, le profileur observe la phase de déroulement mais ne reçoit pas de notification des gestionnaires catch. L'exécution reprend normalement dans du code non managé. Un profileur qui reconnaît du code non managé peut déceler cette situation, mais un profileur de code managé uniquement peut observer un certain nombre d'éléments, parmi lesquels :
rappel ICorProfilerCallback::UnmanagedToManagedTransition lorsque du code non managé appelle du code managé ou retourne à du code managé ;
arrêt d'exécution du thread (si du code non managé se trouvait à la racine du thread) ;
arrêt d'exécution de l'application (si du code non managé ferme l'application).
Gestionnaires CLR
Une exception peut être prise en charge par le Common Language Runtime (CLR) lui-même. Dans ce cas, le profileur observe la phase de déroulement mais ne reçoit pas de notification des gestionnaires catch. Il peut observer la reprise normale de l'exécution dans du code managé ou non managé.
Exceptions non gérées
Par défaut, une exception non gérée n'aboutit pas à l'arrêt de l'exécution du processus dans le .NET Framework version 2.0. Vous pouvez forcer l'adhésion à la stratégie des exceptions du .NET Framework version 1 à l'aide d'un indicateur de compatibilité des applications, comme indiqué dans Exceptions dans les threads managés.