Durée de vie d'un objet : création et destruction des objets

Mise à jour : novembre 2007

Une instance d'une classe, d'un objet est créée à l'aide du mot clé New. Des tâches d'initialisation doivent souvent être effectuées sur les nouveaux objets avant qu'ils ne soient utilisés. Les tâches d'initialisation courantes comprennent l'ouverture de fichiers, la connexion à des bases de données et la lecture de valeurs de clés de Registre. Visual Basic contrôle l'initialisation des nouveaux objets à l'aide de procédures appelées constructeurs (méthodes spéciales permettant de contrôler l'initialisation).

Lorsqu'un objet abandonne la portée, il est libéré par le Common Language Runtime (CLR). Visual Basic contrôle la libération des ressources système à l'aide de procédures nommées destructeurs. Les constructeurs et les destructeurs prennent en charge ensemble la création de bibliothèques de classe robustes et prévisibles.

Sub New et Sub Finalize

Les procédures Sub New et Sub Finalize de Visual Basic initialisent et détruisent des objets ; elles remplacent les méthodes Class_Initialize et Class_Terminate utilisées dans Visual Basic 6.0 et les versions antérieures. Contrairement à Class_Initialize, le constructeur Sub New ne peut s'exécuter qu'après la création d'une classe. Il ne peut être appelé explicitement qu'à partir de la première ligne de code d'un autre constructeur de la même classe ou d'une classe dérivée. En outre, le code dans la méthode Sub New s'exécute toujours avant tout autre code dans une classe. Visual Basic 2005 et les versions ultérieures créent implicitement un constructeur Sub New au moment de l'exécution si vous ne définissez pas explicitement de procédure Sub New pour une classe.

Avant de libérer des objets, le CLR appelle automatiquement la méthode Finalize pour les objets qui définissent une procédure Sub Finalize. La méthode Finalize peut contenir du code qui doit s'exécuter juste avant la destruction d'un objet, par exemple du code pour la fermeture de fichiers et l'enregistrement d'informations d'état. L'exécution de la méthode Sub Finalize réduit légèrement les performances, c'est pourquoi vous ne devez exécuter une méthode Sub Finalize que si vous devez libérer des objets explicitement.

Remarque :

Le garbage collector du CLR ne peut pas supprimer les objets non managés, objets que le système d'exploitation exécute directement, en dehors de l'environnement du CLR. Il en est ainsi parce que les différents objets non managés doivent être supprimés de différentes façons. Ces informations ne sont pas directement associées à l'objet non managé ; elles doivent être recherchées dans la documentation de l'objet. Une classe qui utilise des objets non managés doit les supprimer dans sa méthode Finalize.

Le destructeur Finalize est une méthode protégée qui peut être appelée uniquement à partir de la classe à laquelle elle appartient ou de classes dérivées. Le système appelle automatiquement Finalize lors de la destruction d'un objet, c'est pourquoi il ne faut pas appeler explicitement Finalize depuis l'extérieur de l'implémentation Finalize d'une classe dérivée.

Contrairement à Class_Terminate qui s'exécute dès qu'un objet a une valeur nulle, il y a généralement un délai entre le moment ou un objet perd la portée et le moment où Visual Basic appelle le destructeur Finalize. Visual Basic 2005 et les versions ultérieures autorisent un deuxième type de destructeur, Dispose, qui peut être explicitement appelé à n'importe quel moment pour libérer immédiatement des ressources.

Remarque :

Un destructeur Finalize ne doit pas lever d'exceptions, parce qu'elles ne peuvent pas être gérées par l'application et peuvent provoquer l'arrêt de cette dernière.

Interface IDisposable

Les instances de classe contrôlent souvent les ressources non managées par le CLR, comme les handles Windows et les connexions aux bases de données. Ces ressources doivent être supprimées dans la méthode Finalize de la classe, afin qu'elles soient libérées lorsque l'objet est détruit par le garbage collector. Toutefois, le garbage collector ne détruit les objets que si le CLR requiert plus de mémoire disponible. Cela signifie que les ressources ne peuvent pas être libérées tant que l'objet n'abandonne pas la portée.

Pour compléter le garbage collection, vos classes peuvent fournir un mécanisme permettant de gérer activement les ressources système si elles implémentent l'interface IDisposable. IDisposable a une méthode, Dispose, que les clients doivent appeler lorsqu'ils ont fini d'utiliser un objet. Vous pouvez employer la méthode Dispose pour libérer immédiatement des ressources et effectuer des tâches comme la fermeture de fichiers et les connexions à une base de données. Contrairement au destructeur Finalize, la méthode Dispose n'est pas appelée automatiquement. Les clients d'une classe doivent appeler explicitement Dispose pour pouvoir libérer immédiatement des ressources.

Implémentation de l'interface IDisposable

Une classe qui implémente l'interface IDisposable doit inclure les sections de code ci-dessous :

  • un champ permettant de vérifier la suppression ou non de l'objet :

    Protected disposed As Boolean = False
    
  • surcharge du Dispose qui libère les ressources de la classe. Cette méthode doit être appelée par les méthodes Dispose et Finalize de la classe de base :

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                ' Insert code to free managed resources.
            End If
            ' Insert code to free unmanaged resources.
        End If
        Me.disposed = True
    End Sub
    
  • une implémentation de Dispose qui contient uniquement le code suivant :

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • une substitution de la méthode Finalize qui contient uniquement le code suivant :

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub
    

Dérivation d'une classe qui implémente IDisposable

Une classe qui dérive d'une classe de base implémentant l'interface IDisposable n'a pas besoin de substituer chacune des méthodes de base à moins qu'elle n'utilise des ressources supplémentaires qui doivent être supprimées. Dans cette situation, la classe dérivée doit substituer la méthode Dispose(disposing) de la classe de base pour supprimer les ressources de la classe dérivée. Cette substitution doit appeler la méthode Dispose(disposing) de la classe de base.

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposed Then
        If disposing Then
            ' Insert code to free managed resources.
        End If
        ' Insert code to free unmanaged resources.
    End If
    MyBase.Dispose(disposing)
End Sub

Une classe dérivée ne doit pas substituer les méthodes Dispose et Finalize de la classe de base. Lorsque ces méthodes sont appelées à partir d'une instance de la classe dérivée, l'implémentation de la classe de base de ces méthodes appelle la substitution de la classe dérivée de la méthode Dispose(disposing).

Visualisation

Le diagramme suivant affiche les méthodes qui sont héritées et celles qui sont substituées dans la classe dérivée.

Lorsque ce modèle DisposeFinalize est suivi, les ressources de la classe dérivée et de la classe de base sont supprimées correctement. Le diagramme suivant affiche les méthodes qui sont appelées lorsque les classes sont supprimées et finalisées.

Garbage collection et destructeur Finalize

Le .NET Framework utilise le système garbage collection par traçage des références pour libérer régulièrement les ressources inutiles. Visual Basic 6.0 et les versions antérieures géraient les ressources à l'aide d'un système différent, appelé décompte de références. Bien que ces deux systèmes exécutent la même fonction automatiquement, un certain nombre de différences importantes les distinguent.

Le CLR détruit régulièrement les objets quand le système détermine que ces objets sont devenus inutiles. Les objets sont libérés plus vite en cas de pénurie des ressources système et moins vite dans le cas contraire. Le délai qui sépare le moment où la portée d'un objet se termine et le moment où le CLR libère celui-ci implique qu'il est désormais impossible de déterminer avec précision l'instant où l'objet sera détruit, alors que cela était possible en Visual Basic 6.0 et les versions précédentes. Dans une telle situation, l'on dit que les objets ont une durée de vie non déterminable. Dans la plupart des cas, la durée de vie non déterminable ne modifie en rien la manière dont vous écrivez les applications, à condition de ne pas oublier que le destructeur Finalize ne s'exécutera peut-être pas immédiatement au moment où la portée d'un objet s'achève.

Une autre différence entre les deux systèmes d'opérations garbage collection concerne l'utilisation de Nothing. Pour tirer profit du décompte de références dans Visual Basic 6.0 et les versions précédentes, les programmeurs ont parfois assigné Nothing aux variables objets pour libérer les références contenues dans ces variables. Si la variable contenait la dernière référence à l'objet, les ressources de ce dernier ont été libérées immédiatement. Dans les versions ultérieures de Visual Basic, si l'emploi de cette procédure présente sans doute toujours un intérêt dans certaines situations, il n'entraîne jamais la libération immédiate des ressources de l'objet référencé. Pour libérer immédiatement des ressources, utilisez la méthode Dispose de l'objet, si disponible. La seule situation qui nécessite l'attribution de Nothing à une variable est lorsque cette variable possède une durée de vie qui est longue par rapport à la période requise pour la détection des objets orphelins par le garbage collector.

Voir aussi

Tâches

Comment : implémenter le modèle DisposeFinalize (Visual Basic)

Concepts

Initialisation et suppression des composants

Destructeurs et méthodes Finalize

Référence

Utilisation de constructeurs et de destructeurs

New (Visual Basic)

Dispose

Nothing (Visual Basic)

Autres ressources

Modifications du langage pour les utilisateurs de Visual Basic 6.0