Notions de base du garbage collection

Dans le Common Language Runtime (CLR), le garbage collector a un rôle de gestionnaire de mémoire automatique. Il fournit les avantages suivants :

  • Il vous permet de développer votre application sans avoir à libérer de la mémoire.

  • Il alloue efficacement les objets sur le tas managé.

  • Il libère les objets qui ne sont plus utilisés, efface leur mémoire et garde la mémoire disponible pour les futures allocations. Les objets managés obtiennent automatiquement un contenu propre au démarrage, ce qui fait que leurs constructeurs n'ont pas à initialiser chaque champ de données.

  • Il sécurise la mémoire en s'assurant qu'un objet ne peut pas utiliser le contenu d'un autre objet.

Cette rubrique décrit les concepts fondamentaux du garbage collection. Elle contient les sections suivantes :

  • Notions de base de la mémoire

  • Conditions pour une opération garbage collection

  • Tas managé

  • Générations

  • Déroulement d'une opération garbage collection

  • Manipulation des ressources non managées

  • Garbage collection de station de travail et de serveur

  • Garbage collection simultané

  • Garbage collection d'arrière-plan

Notions de base de la mémoire

La liste suivante résume les concepts importants de la mémoire CLR.

  • Chaque processus possède son propre espace d'adressage virtuel séparé. Tous les processus sur le même ordinateur partagent la même mémoire physique et le fichier d'échange s'il en existe un.

  • Par défaut, sur les ordinateurs 32 bits, chaque processus a un espace d'adressage virtuel en mode utilisateur de 2 Go.

  • En tant que développeur d'applications, vous travaillez uniquement avec l'espace d'adressage virtuel et ne gérez jamais directement la mémoire physique. Le garbage collector alloue et libère la mémoire virtuelle pour vous sur le tas managé.

    Si vous écrivez du code natif, vous utilisez des fonctions Win32 pour utiliser l'espace d'adressage virtuel. Ces fonctions allouent et libèrent la mémoire virtuelle pour vous sur les tas natifs.

  • La mémoire virtuelle peut être dans trois états :

    • Libre. Il n'existe aucune référence au bloc de mémoire et celui-ci est disponible pour allocation.

    • Réservé. Le bloc de mémoire est disponible pour votre utilisation et ne peut pas être utilisé pour une autre demande d'allocation. Toutefois, vous ne pouvez pas stocker de données dans ce bloc de mémoire tant qu'il n'est pas validé.

    • Validé. Le bloc de mémoire est assigné au stockage physique.

  • L'espace d'adressage virtuel peut être fragmenté. Cela signifie qu'il existe des blocs libres, également appelés trous, dans l'espace d'adressage. Lorsqu'une allocation de mémoire virtuelle est demandée, le gestionnaire de mémoire virtuelle doit rechercher un bloc unique libre suffisamment grand pour satisfaire la demande d'allocation. Même si vous disposez de 2 Go d'espace libre, l'allocation qui requiert 2 Go échoue, sauf si tout cet espace est contenu dans un bloc d'adresse unique.

  • Vous pouvez manquer de mémoire si vous manquez d'espace d'adressage virtuel à réserver ou d'espace physique à valider.

Votre fichier d'échange est utilisé, même si la sollicitation de la mémoire physique (c'est-à-dire, la demande de mémoire physique) est faible. La première fois que la sollicitation de la mémoire physique est élevée, le système d'exploitation doit libérer de la place dans la mémoire physique pour stocker des données et sauvegarde une partie des données qui sont dans la mémoire physique dans le fichier d'échange. Ces données ne sont pas paginées tant qu'elles ne sont pas nécessaires, il est donc possible de rencontrer la pagination dans les situations dans lesquelles la sollicitation de la mémoire physique est très faible.

Retour au début

Conditions pour une opération garbage collection

Le garbage collection se produit lorsque l'une des conditions suivantes est vraie :

  • Le système possède peu de mémoire physique.

  • La mémoire utilisée par les objets alloués sur le tas managé dépasse un seuil acceptable. Cela signifie qu'un seuil d'utilisation de la mémoire acceptable a été dépassé sur le tas managé. Ce seuil est continuellement ajusté à mesure que le processus s'exécute.

  • La méthode GC.Collect est appelée. Dans presque tous les cas, vous n'avez pas à appeler cette méthode, car le garbage collector s'exécute continuellement. Cette méthode est principalement utilisée pour les situations uniques et les tests.

Retour au début

Tas managé

Une fois que le garbage collector est initialisé par le CLR, il alloue un segment de mémoire pour stocker et gérer des objets. Cette mémoire est appelée tas managé, par opposition à un tas natif dans le système d'exploitation.

Il existe un tas managé pour chaque processus managé. Tous les threads du processus allouent des objets sur le même tas.

Pour réserver de la mémoire, le garbage collector appelle la fonction Win32 VirtualAlloc et réserve un segment de mémoire à la fois pour les applications managées. Le garbage collector réserve également les segments nécessaires et libère des segments dans le système d'exploitation (après avoir effacé tous leurs objets) en appelant la fonction VirtualFree (page éventuellement en anglais) Win32.

Moins il y a d'objets alloués sur le tas, moins le garbage collector a à faire. Lorsque vous allouez des objets, n'utilisez pas de valeurs arrondies qui dépassent vos besoins, par exemple en allouant un tableau de 32 octets lorsque vous avez besoin de seulement 15 octets.

Lorsqu'un garbage collection est déclenché, le garbage collector libère la mémoire occupée par les objets morts. Le processus de libération compacte les objets vivants afin qu'ils soient déplacés ensemble, et l'espace inutilisé est supprimé, ce qui entraîne la diminution du tas. Les objets alloués ensemble restent ainsi ensemble sur le tas managé, pour conserver leur emplacement.

Le déroulement (fréquence et durée) des garbage collection est le résultat du volume des allocations et de la quantité de mémoire restante sur le tas managé.

Le tas peut être considéré comme l'accumulation de deux tas : le tas d'objets volumineux et le tas de petits objets.

Le tas d'objets volumineux contient des objets faisant au moins 85 000 octets. Les très grands objets du tas d'objets volumineux sont généralement des tableaux. Il est rare qu'un objet d'instance soit extrêmement grand.

Retour au début

Générations

Le tas est organisé en générations. Il peut ainsi gérer des objets durables et éphémères. Le garbage collection consiste principalement en la récupération d'objets éphémères qui occupent généralement une petite partie du tas. Il existe trois générations d'objets sur le tas :

  • Génération 0. Il s'agit de la génération la plus jeune, qui contient des objets éphémères. Un exemple d'objet éphémère est une variable temporaire. Le garbage collection a le plus souvent lieu dans cette génération.

    Les objets alloués récemment forment une nouvelle génération d'objets et sont implicitement des collections de génération 0, à moins qu'ils ne s'agissent de grands objets, auquel cas ils entrent dans le tas d'objets volumineux dans une collection de génération 2.

    La plupart des objets sont libérés pour l'opération garbage collection dans la génération 0 et ne survivent pas à la génération suivante.

  • Génération 1. Cette génération contient des objets éphémères et sert de tampon entre objets éphémères et objets durables.

  • Génération 2. Cette génération contient des objets durables. Un exemple d'objet durable est un objet dans une application serveur qui contient des données statiques qui sont vivantes pour la durée du processus.

Les opérations garbage collection se produisent sur des générations spécifiques, selon les conditions spécifiées. La collecte d'une génération signifie la collecte des objets de cette génération et de toutes ses générations plus jeunes. Les opérations garbage collection de génération 2 sont également appelées garbage collection complet, car elles libèrent tous les objets de toutes les générations (autrement dit, tous les objets du tas managé).

Survie et promotions

Les objets qui ne sont pas libérés dans un garbage collection sont appelé survivants et sont promus à la génération suivante. Les objets qui survivent à un garbage collection de génération 0 sont promus à la génération 1, les objets qui survivent à un garbage collection de génération 1 sont promus à la génération 2 et les objets qui survivent à un garbage collection de génération 2 restent dans la génération 2.

Lorsque le garbage collector détecte que le taux de survie est élevé dans une génération, il augmente le seuil des allocations de cette génération. La collecte suivante récupère donc une taille substantielle de mémoire libérée. Le CLR équilibre continuellement deux priorités : ne pas permettre au jeu de travail d'une application de devenir trop grand et ne pas permettre pas au garbage collection d'être trop long.

Segments et générations éphémères

Étant donné que les objets des générations 0 et 1 sont éphémères, ces générations sont appelées générations éphémères.

Les générations éphémères doivent être allouées dans le segment de mémoire appelé segment éphémère. Chaque nouveau segment acquis par le garbage collector devient le nouveau segment éphémère et contient les objets qui ont survécu à un garbage collection de génération 0. L'ancien segment éphémère devient le nouveau segment de génération 2.

Le segment éphémère peut inclure des objets de la génération 2. Les objets de génération 2 peuvent utiliser plusieurs segments (autant que votre processus en requiert et que la mémoire en autorise).

La quantité de mémoire libérée à partir d'un garbage collection éphémère est limitée à la taille du segment éphémère. La quantité de mémoire libérée est proportionnelle à l'espace occupé par les objets morts.

Retour au début

Déroulement d'une opération garbage collection

Une opération garbage collection présente les phases suivantes :

  • Une phase de marquage qui recherche et crée une liste de tous les objets actifs.

  • Une phase de déplacement qui met à jour les références aux objets qui seront compactés.

  • Une phase de compactage qui libère l'espace occupé par les objets morts et compacte les objets survivants. La phase de compactage déplace les objets qui ont survécu à un garbage collection vers l'extrémité la plus ancienne du segment.

    Étant donné que les collections de génération 2 peuvent occuper plusieurs segments, les objets promus dans la génération 2 peuvent être déplacés dans un segment plus ancien. Les survivants des générations 1 et 2 peuvent être déplacés vers un autre segment, car ils sont promus à la génération 2.

    Le tas d'objets volumineux n'est pas compacté, car cela augmenterait l'utilisation de la mémoire sur une durée inacceptable.

Le garbage collector utilise les informations suivantes pour déterminer si les objets sont vivants :

  • Racines de pile. Variables de pile fournies par le compilateur juste-à-temps (JIT) et l'explorateur de pile.

  • Handles de garbage collection. Handles qui pointent vers les objets managés qui peuvent être alloués par le code utilisateur ou par le Common Language Runtime.

  • Données statiques. Objets statiques des domaines d'application qui pourraient référencer d'autres objets. Chaque domaine d'application effectue le suivi de ses objets statiques.

Avant qu'une opération garbage collection ne démarre, tous les threads managés sont suspendus à l'exception du thread qui a déclenché l'opération.

L'illustration suivante montre un thread qui déclenche un garbage collection et entraîne l'interruption des autres threads.

Thread qui déclenche un garbage collection

Lorsqu'un thread déclenche un nettoyage de la mémoire

Retour au début

Manipulation des ressources non managées

Si vos objets managés référencent des objets non managés à l'aide de leurs handles de fichiers natifs, vous devez libérer les objets managés explicitement, car le garbage collector effectue le suivi de la mémoire uniquement sur le tas managé.

Les utilisateurs de votre objet managé ne peuvent pas supprimer les ressources natives utilisées par l'objet. Pour effectuer le nettoyage, vous pouvez rendre votre objet managé finalisable. La finalisation est constituée des actions de nettoyage que vous exécutez lorsque l'objet n'est plus utilisé. Lorsque votre objet managé meurt, il effectue les actions de nettoyage spécifiées dans sa méthode de finaliseur.

Lorsqu'un objet finalisable est détecté comme étant mort, son finaliseur est placé dans une file d'attente afin que ses actions de nettoyage soient exécutées, mais l'objet lui-même est promu à la génération suivante. Par conséquent, vous devez attendre jusqu'au garbage collection suivant sur cette génération (qui n'est pas nécessairement le garbage collection suivant) pour déterminer si l'objet a été récupéré.

Retour au début

Garbage collection de station de travail et de serveur

Le garbage collector s'ajuste automatiquement et peut travailler dans une large gamme de scénarios. La seule option que vous pouvez définir est le type de garbage collection, en fonction des caractéristiques de la charge de travail. Le CLR fournit les types de garbage collection suivants :

  • Garbage collection de station de travail, pour toutes les stations de travail clientes et les PC autonomes. Il s'agit du paramètre par défaut pour l'élément <gcServer> dans le schéma de configuration d'exécution.

    Le garbage collection de station de travail peut être simultané ou non simultané. Le garbage collection simultané permet aux threads managés de continuer à fonctionner pendant un garbage collection.

    En commençant par le .NET Framework version 4, le garbage collection d'arrière-plan remplace le garbage collection simultané. 

  • Garbage collection de serveur, prévu pour les applications serveur qui ont besoin d'un débit et d'une montée en charge élevés.

Les illustrations suivantes montrent les threads dédiés qui exécutent le garbage collection sur un serveur.

Garbage collection de serveur

Threads de nettoyage de la mémoire du serveur

Configuration du garbage collection

Vous pouvez utiliser l'élément <gcServer> du schéma de configuration d'exécution pour spécifier le type de garbage collection vous souhaitez que le CLR exécute. Lorsque l'attribut enabled de cet élément a la valeur false (valeur par défaut), le CLR exécute le garbage collection de station de travail. Lorsque vous affectez à l'attribut enabled la valeur true, le CLR exécute le garbage collection de serveur.

Le garbage collection simultané est spécifié par l'élément <gcConcurrent> du schéma de configuration d'exécution. Le paramètre par défaut est enabled. Le garbage collection simultané est uniquement disponible pour le garbage collection de station de travail et n'a aucun effet sur le garbage collection de serveur.

Vous pouvez également spécifier le garbage collection de serveur avec des interfaces d'hébergement non managées. Notez que ASP.NET et SQL Server activent automatiquement le garbage collection de serveur si votre application est hébergée dans un de ces environnements.

Comparaison des garbage collection de station de travail et de serveur

Considérations liées aux threads et aux performances pour le garbage collection de station de travail :

  • La collecte se produit sur le thread utilisateur qui a déclenché le garbage collection et reste à la même priorité. Étant donné que les threads utilisateur sont généralement exécutés à la priorité normale, le garbage collector (qui s'exécute sur un thread de priorité normale) doit rivaliser avec d'autres threads pour le temps processeur.

    Les threads qui exécutent du code natif ne sont pas interrompus.

  • Le garbage collection de station de travail est toujours utilisé sur un ordinateur à un seul processeur, indépendamment du paramètre <gcServer>. Si vous spécifiez le garbage collection de serveur, le CLR utilise le garbage collection de station de travail avec la concurrence désactivée.

Considérations liées aux threads et aux performances pour le garbage collection de serveur :

  • La collecte se produit sur plusieurs threads dédiés qui s'exécutent au niveau de priorité THREAD_PRIORITY_HIGHEST.

  • Un thread dédié pour effectuer le garbage collection et un tas sont fournis pour chaque UC, et les tas sont collectés en même temps. Chaque tas contient un tas de petits objets et un tas d'objets volumineux, et tous les tas peuvent faire l'objet d'accès par du code utilisateur. Les objets des différents tas peuvent faire référence les uns aux autres.

  • Étant donné que plusieurs threads de garbage collection fonctionnent ensemble, le garbage collection de serveur est plus rapide que le garbage collection de station de travail sur un tas de même taille.

  • Le garbage collection de serveur présente souvent des segments de plus grande taille.

  • Le garbage collection de serveur peut consommer beaucoup de ressources. Par exemple, si vous disposez de 12 processus qui s'exécutent sur un ordinateur possédant 4 processeurs, il y aura 48 threads de garbage collection dédiés s'ils utilisent tous le garbage collection de serveur. Dans une situation de charge de mémoire élevée, si tous les processus commencent le garbage collection, le garbage collector aura 48 threads à planifier.

Si vous exécutez des centaines d'instances d'une application, envisagez d'utiliser le garbage collection de station de travail avec le garbage collection simultané désactivé. Cela provoquera moins de changements de contexte, ce qui peut améliorer les performances.

Retour au début

Garbage collection simultané

Avec le garbage collection de station de travail, vous pouvez activer le garbage collection simultané, ce qui permet aux threads de fonctionner simultanément avec un thread dédié qui exécute le garbage collection pendant une grande partie de la durée de ce dernier. Cette option affecte uniquement les opérations garbage collection de génération 2. Les générations 0 et 1 sont toujours non simultanées car elles se terminent très rapidement.

Le garbage collection simultané permet aux applications interactives d'être plus réactives en réduisant les pauses d'une collection. Les threads managés peuvent continuer à s'exécuter une grande partie de la durée du garbage collection simultané. Cela génère des pauses plus courtes pendant l'opération garbage collection.

Pour améliorer les performances lorsque plusieurs processus s'exécutent, désactivez le garbage collection simultané.

Le garbage collection simultané est exécuté sur un thread dédié. Par défaut, le CLR effectue le garbage collection de station de travail avec le garbage collection simultané activé. Ceci est vrai pour les ordinateurs multiprocesseur et à processeur unique.

Votre capacité à allouer de petits objets sur le tas pendant un garbage collection simultané est limitée par les objets restants dans le segment éphémère lorsqu'une opération garbage collection simultanée démarre. Dès que vous atteignez la fin du segment, vous devez attendre que le garbage collection simultané se termine pendant que les threads managés qui doivent effectuer les allocations des petits objet sont interrompus.

Le garbage collection simultané possède un jeu de travail légèrement plus grand (comparé au garbage collection non simultané) car vous pouvez allouer des objets pendant la collecte simultanée. Toutefois, cela peut affecter les performances, car les objets que vous allouez deviennent une partie de votre jeu de travail. Essentiellement, le garbage collection simultané échange de l'UC et de la mémoire contre des pauses plus courtes.

L'illustration suivante montre le garbage collection simultané exécuté sur un thread dédié différent.

Garbage collection simultané

Threads de nettoyage de la mémoire simultanés

Retour au début

Garbage collection d'arrière-plan

Avec le garbage collection d'arrière-plan, les générations éphémères (0 et 1) sont collectées si nécessaire pendant la collecte de la génération 2. Il n'y a aucun paramètre pour le garbage collection d'arrière-plan. Il est automatiquement activé avec le garbage collection simultané. Le garbage collection d'arrière-plan vient en remplacement du garbage collection simultané. Comme le garbage collection simultané, le garbage collection d'arrière-plan est exécuté sur un thread dédié et est uniquement applicable aux collections de génération 2.

RemarqueRemarque

Le garbage collection d'arrière-plan est uniquement disponible dans le .NET Framework 4 et les versions ultérieures.

Une collecte sur des générations éphémères pendant le garbage collection d'arrière-plan est appelée garbage collection de premier plan. Lorsque des opérations garbage collection de premier plan ont lieu, tous les threads managés sont suspendus.

Lorsque le garbage collection d'arrière-plan est en cours et que vous avez alloué assez d'objets dans la génération 0, le CLR exécute un garbage collection de premier plan de génération 0 ou 1. Le thread de garbage collection d'arrière-plan dédié vérifie des points sécurisés fréquents de façon à déterminer s'il existe une demande de garbage collection de premier plan. Le cas échéant, la collecte d'arrière-plan s'interrompt afin que le garbage collection de premier plan puisse se produire. Une fois le garbage collection de premier plan terminé, le thread de garbage collection d'arrière-plan dédié et les threads utilisateur reprennent.

Le garbage collection d'arrière-plan supprime les restrictions d'allocation imposées par le garbage collection simultané, car des opérations garbage collection éphémères peuvent se produire pendant le garbage collection d'arrière-plan. Cela signifie que le garbage collection d'arrière-plan peut supprimer des objets morts dans les générations éphémères et peut également développer le tas si nécessaire pendant un garbage collection de génération 1.

Le garbage collection d'arrière-plan n'est actuellement pas disponible pour le garbage collection de serveur.

Retour au début

Voir aussi

Concepts

Garbage Collection