Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Remarque
Cet article est spécifique à .NET Framework. Elle ne s’applique pas aux implémentations plus récentes de .NET, notamment .NET 6 et versions ultérieures.
Les systèmes d’exploitation et les environnements d’exécution fournissent généralement une forme d’isolation entre les applications. Par exemple, Windows utilise des processus pour isoler les applications. Cette isolation est nécessaire pour s’assurer que le code s’exécutant dans une application ne peut pas affecter d’autres applications non liées.
Les domaines d’application constituent une limite d’isolation pour la sécurité, la fiabilité, le contrôle de version, ainsi que pour le déchargement des assemblages. Les domaines d’application sont généralement créés par des hôtes d’exécution, qui sont responsables du démarrage du Common Language Runtime avant l’exécution d’une application.
Avantages de l’isolation des applications
Historiquement, les limites de processus ont été utilisées pour isoler les applications s’exécutant sur le même ordinateur. Chaque application est chargée dans un processus distinct, qui isole l’application des autres applications s’exécutant sur le même ordinateur.
Les applications sont isolées, car les adresses mémoire sont relatives aux processus ; Un pointeur de mémoire passé d’un processus à un autre ne peut pas être utilisé de manière significative dans le processus cible. En outre, vous ne pouvez pas effectuer d’appels directs entre deux processus. Au lieu de cela, vous devez utiliser des proxys, qui fournissent un niveau d’indirection.
Le code managé doit être transmis via un processus de vérification avant de pouvoir être exécuté (sauf si l’administrateur a accordé l’autorisation d’ignorer la vérification). Le processus de vérification détermine si le code peut tenter d’accéder aux adresses mémoire non valides ou d’effectuer une autre action susceptible de provoquer l’échec du processus dans lequel il s’exécute correctement. Le code qui réussit le test de vérification est dit être de type sécurisé. La possibilité de vérifier le code en tant que type sécurisé permet au Common Language Runtime de fournir un niveau d’isolation aussi élevé que la limite de processus, à un coût de performances beaucoup plus faible.
Les domaines d’application fournissent une unité de traitement plus sécurisée et polyvalente que le Common Language Runtime peut utiliser pour assurer l’isolation entre les applications. Vous pouvez exécuter plusieurs domaines d’application dans un seul processus avec le même niveau d’isolation que celui qui existerait dans des processus distincts, mais sans entraîner de surcharge supplémentaire pour effectuer des appels inter-processus ou basculer entre les processus. La possibilité d’exécuter plusieurs applications au sein d’un seul processus augmente considérablement la scalabilité du serveur.
L’isolation des applications est également importante pour la sécurité des applications. Par exemple, vous pouvez exécuter des contrôles à partir de plusieurs applications web dans un seul processus de navigateur de telle sorte que les contrôles ne peuvent pas accéder aux données et ressources des uns et des autres.
L’isolation fournie par les domaines d’application présente les avantages suivants :
Les erreurs dans une application ne peuvent pas affecter d’autres applications. Étant donné que le code de type sécurisé ne peut pas provoquer d’erreurs de mémoire, l’utilisation de domaines d’application garantit que le code s’exécutant dans un domaine ne peut pas affecter d’autres applications dans le processus.
Les applications individuelles peuvent être arrêtées sans arrêter l’ensemble du processus. L’utilisation de domaines d’application vous permet de décharger le code en cours d’exécution dans une seule application.
Remarque
Vous ne pouvez pas décharger des assemblages ou des types individuels. Seul un domaine complet peut être déchargé.
Le code exécuté dans une application ne peut pas accéder directement au code ou aux ressources d’une autre application. Le Common Language Runtime applique cette isolation en empêchant les appels directs entre les objets dans différents domaines d’application. Les objets qui passent entre les domaines sont copiés ou accessibles par proxy. Si l’objet est copié, l’appel à l’objet est local. Autrement dit, l’appelant et l’objet référencé se trouvent dans le même domaine d’application. Si l’objet est accessible via un proxy, l’appel à l’objet est distant. Dans ce cas, l’appelant et l’objet référencés se trouvent dans différents domaines d’application. Les appels inter-domaines utilisent la même infrastructure d’appels distants que les appels entre deux processus ou entre deux ordinateurs. Par conséquent, les métadonnées de l’objet référencé doivent être disponibles pour les deux domaines d’application pour permettre à l’appel de méthode d’être compilé correctement par JIT. Si le domaine appelant n’a pas accès aux métadonnées de l’objet appelé, la compilation peut échouer avec une exception de type FileNotFoundException. Pour plus d’informations, consultez Objets distants. Le mécanisme permettant de déterminer la façon dont les objets sont accessibles entre les domaines est déterminé par l’objet. Pour plus d’informations, consultez System.MarshalByRefObject.
Le comportement du code est limité par l’application dans laquelle elle s’exécute. En d’autres termes, le domaine d’application fournit des paramètres de configuration tels que les stratégies de version d’application, l’emplacement des assemblys distants auxquels il accède et des informations sur l’emplacement où localiser les assemblys chargés dans le domaine.
Les autorisations accordées au code peuvent être contrôlées par le domaine d’application dans lequel le code est en cours d’exécution.
Domaines d’application et assemblys
Cette section décrit la relation entre les domaines d’application et les assemblys. Vous devez charger un assembly dans un domaine d’application avant de pouvoir exécuter le code qu’il contient. L’exécution d’une application classique entraîne le chargement de plusieurs assemblys dans un domaine d’application.
La façon dont un assembly est chargé détermine si son code compilé juste-à-temps (JIT) peut être partagé par plusieurs domaines d’application dans le processus et si l’assembly peut être déchargé à partir du processus.
Si un assembly est chargé sans domaine, tous les domaines d’application qui partagent le même jeu d’octrois de sécurité peuvent partager le même code compilé JIT, ce qui réduit la mémoire requise par l’application. Toutefois, l'assembly ne peut jamais être déchargé du processus.
Si un assembly n’est pas chargé de manière indépendante du domaine, il doit être compilé par JIT dans chaque domaine d’application dans lequel il est chargé. Toutefois, l'assemblage peut être déchargé du processus en déchargeant tous les domaines d'application dans lesquels il est chargé.
L'hôte de l'environnement d'exécution détermine s'il faut charger des assemblages en tant qu'assemblages neutres dans le domaine lorsqu'il charge l'environnement d'exécution dans un processus. Pour les applications gérées, appliquez l’attribut LoaderOptimizationAttribute à la méthode de point d’entrée du processus et spécifiez une valeur de l’énumération associée LoaderOptimization . Pour les applications non managées qui hébergent le Common Language Runtime, spécifiez l’indicateur approprié lorsque vous appelez la méthode CorBindToRuntimeEx Function .
Il existe trois options de chargement des assemblys indépendants du domaine :
LoaderOptimization.SingleDomain ne charge aucun assembly comme indépendant du domaine, sauf Mscorlib, qui est toujours chargé comme indépendant du domaine. Ce paramètre est appelé domaine unique, car il est couramment utilisé lorsque l’hôte exécute une seule application dans le processus.
LoaderOptimization.MultiDomain charge tous les assemblys comme indépendants du domaine. Utilisez ce paramètre lorsqu’il existe plusieurs domaines d’application dans le processus, qui exécutent tous le même code.
LoaderOptimization.MultiDomainHost charge les assemblys avec nom fort comme indépendants du domaine s’ils ont été installés, ainsi que toutes leurs dépendances, dans le Global Assembly Cache. D’autres assemblies sont chargées et compilées séparément pour chaque domaine d’application dans lequel elles sont chargées, et peuvent donc être déchargées du processus. Utilisez ce paramètre lors de l’exécution de plusieurs applications dans le même processus, ou si vous avez un mélange d’assemblys partagés par de nombreux domaines d’application et assemblys qui doivent être déchargés à partir du processus.
Le code compilé juste-à-temps ne peut pas être partagé pour les assemblys chargés dans le contexte de chargement, à l'aide de la méthode LoadFrom de la classe Assembly, ou chargés à partir d'images à l'aide de surcharges de la méthode Load qui spécifient des tableaux d'octets.
Les assemblys qui ont été compilés en code natif à l’aide de l' Ngen.exe (Générateur d’images natives) peuvent être partagés entre les domaines d’application, s’ils sont chargés de manière indépendante du domaine la première fois qu’ils sont chargés dans un processus.
Le code compilé JIT pour l’assembly qui contient le point d’entrée de l’application est partagé uniquement si toutes ses dépendances peuvent être partagées.
Un assembly indépendant du domaine peut être compilé juste-à-temps plusieurs fois. Par exemple, lorsque les jeux d’octrois de sécurité de deux domaines d’application sont différents, ils ne peuvent pas partager le même code compilé par JIT. Toutefois, chaque copie de l'assembly compilé juste-à-temps peut être partagée avec d'autres domaines d'application disposant du même jeu d'autorisations.
Lorsque vous décidez de charger des assemblages en tant qu'assemblage neutre par domaine, vous devez évaluer le compromis entre la réduction de l'utilisation de la mémoire et d'autres facteurs de performance.
L'accès aux données statiques et aux méthodes est plus lent pour les assemblies neutres vis-à-vis du domaine en raison de la nécessité d'isoler ces assemblies. Chaque domaine d’application qui accède à l’assembly doit avoir une copie distincte des données statiques pour empêcher les références aux objets dans des champs statiques de traverser les limites du domaine. Par conséquent, le runtime contient une logique supplémentaire pour diriger un appelant vers la copie appropriée des données statiques ou de la méthode. Cette logique supplémentaire ralentit l'appel.
Toutes les dépendances d’un assembly doivent être localisées et chargées lorsque l’assembly est chargé de manière indépendante du domaine, car une dépendance qui ne peut pas être chargée de type domaine neutre empêche l’assembly d’être chargé de manière neutre dans le domaine.
Domaines et threads d’application
Un domaine d’application constitue une limite d’isolation pour la sécurité, le contrôle de version, la fiabilité et le déchargement du code managé. Un thread est la construction du système d’exploitation utilisée par le Common Language Runtime pour exécuter du code. Au moment de l’exécution, tout le code managé est chargé dans un domaine d’application et est exécuté par un ou plusieurs threads managés.
Il n’existe pas de corrélation un-à-un entre les domaines d’application et les threads. Plusieurs threads peuvent s’exécuter dans un domaine d’application unique à tout moment, et un thread particulier n’est pas limité à un seul domaine d’application. Autrement dit, les threads sont libres de traverser les limites du domaine d’application ; Un nouveau thread n’est pas créé pour chaque domaine d’application.
À tout moment, chaque thread s’exécute dans un domaine d’application. Zéro, un ou plusieurs threads peuvent s’exécuter dans un domaine d’application donné. Le runtime effectue le suivi des threads qui s’exécutent dans les domaines d’application. Vous pouvez localiser le domaine dans lequel un thread s’exécute à tout moment en appelant la Thread.GetDomain méthode.
Domaines et cultures d’application
La culture, représentée par un CultureInfo objet, est associée aux threads. Vous pouvez obtenir la culture associée au thread en cours d’exécution à l’aide de la CultureInfo.CurrentCulture propriété, et vous pouvez obtenir ou définir la culture associée au thread en cours d’exécution à l’aide de la Thread.CurrentCulture propriété. Si la culture associée à un thread a été explicitement définie à l’aide de la Thread.CurrentCulture propriété, elle continue d’être associée à ce thread lorsque le thread traverse les limites du domaine d’application. Sinon, la culture associée au thread à un moment donné est déterminée par la valeur de la CultureInfo.DefaultThreadCurrentCulture propriété dans le domaine d’application dans lequel le thread s’exécute :
Si la valeur de la propriété n’est pas
null
, la culture retournée par la propriété est associée au thread (et par conséquent retournée par les propriétés Thread.CurrentCulture et CultureInfo.CurrentCulture).Si la valeur de la propriété est
null
, la culture système en cours est associée au thread.
Programmation avec des domaines d’application
Les domaines d’application sont généralement créés et manipulés par programme par les hôtes runtime. Toutefois, parfois, un programme d’application peut également vouloir utiliser des domaines d’application. Par exemple, un programme d’application peut charger un composant d’application dans un domaine pour pouvoir décharger le domaine (et le composant) sans avoir à arrêter toute l’application.
Le AppDomain est l’interface programmatique des domaines d’application. Cette classe inclut des méthodes pour créer et décharger des domaines, créer des instances de types dans des domaines et s’inscrire à différentes notifications telles que le déchargement de domaine d’application. Le tableau suivant répertorie les méthodes couramment utilisées AppDomain .
Méthode AppDomain | Descriptif |
---|---|
CreateDomain | Crée un domaine d’application. Il est recommandé d’utiliser une surcharge de cette méthode qui spécifie un AppDomainSetup objet. Il s’agit de la méthode recommandée pour définir les propriétés d’un nouveau domaine, comme la base de l’application ou le répertoire racine de l’application ; l’emplacement du fichier de configuration pour le domaine ; et le chemin de recherche que le Common Language Runtime doit utiliser pour charger des assemblys dans le domaine. |
ExecuteAssembly et ExecuteAssemblyByName | Exécute un assembly dans le domaine d’application. Il s’agit d’une méthode d’instance, afin qu’elle puisse être utilisée pour exécuter du code dans un autre domaine d’application auquel vous avez une référence. |
CreateInstanceAndUnwrap | Crée une instance d’un type spécifié dans le domaine d’application et retourne un proxy. Utilisez cette méthode pour éviter de charger l'assembly qui contient le type créé dans l'assembly appelant. |
Unload | Effectue un arrêt approprié du domaine. Le domaine d’application n’est pas déchargé tant que tous les threads s’exécutant dans le domaine n’ont pas été arrêtés ou ne sont plus dans le domaine. |
Remarque
Le Common Language Runtime ne prend pas en charge la sérialisation des méthodes globales. Les délégués ne peuvent donc pas être utilisés pour exécuter des méthodes globales dans d’autres domaines d’application.
Les interfaces non managées décrites dans la spécification des interfaces d’hébergement common language runtime fournissent également l’accès aux domaines d’application. Les hôtes runtime peuvent utiliser des interfaces à partir de code non managé pour créer et accéder aux domaines d’application au sein d’un processus.
Variable d’environnement COMPLUS_LoaderOptimization
Variable d’environnement qui définit la stratégie d’optimisation du chargeur par défaut d’une application exécutable.
Syntaxe
COMPLUS_LoaderOptimization = 1
Remarques
Une application classique charge plusieurs assemblys dans un domaine d’application avant que le code qu’ils contiennent puisse être exécuté.
La façon dont l'assembly est chargé détermine si son code compilé juste-à-temps (JIT) peut être partagé par plusieurs domaines d'application dans le processus.
Si un assembly est chargé de manière indépendante du domaine, tous les domaines d’application qui partagent le même jeu d’octrois de sécurité peuvent partager le même code compilé par JIT. Cela réduit la mémoire requise par l’application.
Si un assembly n’est pas chargé de type domaine neutre, il doit être compilé par JIT dans chaque domaine d’application dans lequel il est chargé et le chargeur ne doit pas partager les ressources internes entre les domaines d’application.
Lorsque la valeur est définie sur 1, l’indicateur d’environnement COMPLUS_LoaderOptimization force l’hôte d’exécution à charger tous les assemblys de la manière non neutre du domaine appelée SingleDomain. SingleDomain ne charge aucun assembly comme indépendant du domaine, sauf Mscorlib, qui est toujours chargé comme indépendant du domaine. Ce paramètre est appelé domaine unique, car il est couramment utilisé lorsque l’hôte exécute une seule application dans le processus.
Avertissement
L’indicateur d’environnement COMPLUS_LoaderOptimization a été conçu pour être utilisé dans les scénarios de diagnostic et de test. L’activation de l’indicateur peut entraîner un ralentissement grave et une augmentation de l’utilisation de la mémoire.
Exemple de code
Pour forcer tous les assemblys à ne pas se charger comme indépendants du domaine pour le service IISADMIN, ajoutez COMPLUS_LoaderOptimization=1
à la chaîne de valeur multiple de l'environnement dans la clé HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN.
Key = HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\IISADMIN
Name = Environment
Type = REG_MULTI_SZ
Value (to append) = COMPLUS_LoaderOptimization=1