destruction en règle d'un objet perso en .NET

destruction en règle d'un objet perso en .NET - C#/.NET managed - Programmation

Marsh Posté le 29-03-2007 à 16:32:00    

Hello tout le monde,
 
Voilà j'ai une lacune à combler en VB.NET (ou .net en général).
Dans une appli, j'instancie une class de ma conception (qui contient divers autres objets comme des timers, des sockets etc), elle devient donc un objet et pour le garder en vie une fois sortie de la procédure qui l'a créé, je l'ajoute dans une collection d'objet (qui est public).
 
Cependant je ne sais pas comment détruire cet objet lorsque je n'en ai plus besoin.
En effet je pensais que le fait de supprimer l'objet de la collection suffirait à détruire le dernier pointeur existant et donc détruirait l'objet, mais une fois ceci fait, je constate via des points d'arrêt que les timers dans mon objet continue de se déclencher, ce qui prouve que l'objet vit toujours quelque part !
 
Merci de m'éclairer concernant ce concept, et de me dire comment faire afin que je puisse détruire définitivement mes objets.
 
Cordialement

Reply

Marsh Posté le 29-03-2007 à 16:32:00   

Reply

Marsh Posté le 29-03-2007 à 17:39:22    

essaie de lui affecter "null" (ou "nothing" en vb) avant de le supprimer de la collection.
 
vérifie aussi que tu arrêtes bien tes timers dans ton destructeur.
 
mais pour faire proprement, tu dois le faire dériver de IDisposable et ajouter une méthode public "Dispose()" qui effectue tout ce travail de nettoyage. (à ce moment, le destructeur fait un appel à Dispose() puis éventuellement détruit quelques petits bouts en plus)

Reply

Marsh Posté le 29-03-2007 à 18:35:30    

Salut à toi et merci pour pour ton aide.
 
Lui affecter nothing ne sert n'aura servi à rien, si ce n'est qu'à détruire le pointeur auquel j'ai assigné nothing. L'objet lui, continue son chemin.
 
En revanche ta seconde proposition me semble très approprié !
Comment faire pour dériver ma class en IDisposable ?
Quand tu dis le destructeur fait un appel à Dispose(), c'est automatique ou c'est à moi d'appeler ma méthode public Dispose ?
 
Si je comprends bien donc, je dois donc faire le travail de nettoyage moi-même à l'intérieur même de ma classe. Toutefois si j'arrête à la mano les timers, comment saurais-je une fois qu'ils sont arrêtés, que la class est vraiment détruite ?
 
Quelqu'un peut-il me poster un exemple de ces sub dispose & compagnie ?
 
Merci beaucoup.

Reply

Marsh Posté le 29-03-2007 à 19:09:14    

public class maClass : IDisposable
{
    object maVariable;
 
    public maClass()
    {
       maVariable = new ...;
    }
 
    public void Dispose()
    {
        if (maVariable != null)
        {
            maVariable.Dispose(); // Important pour un timer par exemple, qui pourraît bien s'autoréférencer ailleurs que dans ton objet, notamment parcequ'un timer tourne dans un thread séparé
            maVariable = null;
        }
    }
 
    ~maClass()
    {
        Dispose();
        // Eventuellement d'autres ménages
    }
}
 
 
maClass test = new maClass();
maCollection.Add(test);
maCollection[0].Dispose(); // Normalement, cette ligne est inutile, puisque le destructeur est censé être appelé
maCollection.RemoveAt(0);


Message édité par MagicBuzz le 29-03-2007 à 19:10:25
Reply

Marsh Posté le 29-03-2007 à 19:13:52    

MagicBuzz a écrit :

essaie de lui affecter "null" (ou "nothing" en vb) avant de le supprimer de la collection.
 
vérifie aussi que tu arrêtes bien tes timers dans ton destructeur.
 
mais pour faire proprement, tu dois le faire dériver de IDisposable et ajouter une méthode public "Dispose()" qui effectue tout ce travail de nettoyage. (à ce moment, le destructeur fait un appel à Dispose() puis éventuellement détruit quelques petits bouts en plus)


 
ca implémente l'interface IDisposable, ca n'en dérive pas.

Reply

Marsh Posté le 29-03-2007 à 19:16:01    

ouais, chuis pas trop fluent avec les dénomination :ange:
 
"tu fourres le truc dans le bidule et quand tu machine le bignou ça proutch" <= c'est tellement plus clair :D

Reply

Marsh Posté le 30-03-2007 à 00:03:51    

Reply

Marsh Posté le 30-03-2007 à 09:25:19    

Merci à tous pour vos explications !
 
 
Toutefois je me retrouve maintenant avec 2 solutions, mais laquelle choisir ?
Harkonnen m'a pointé vers le fonctionnement de Finalize qui est donc finalement la même chose plus ou moins que Dispose puisque j'y ferais le ménage.
 
Mais que faire ? Dispose ou Finalize ?
Le mieux niveau nettoyage, vitesse, ressource, c'est quoi ?
 
 
Merci encore.

Reply

Marsh Posté le 30-03-2007 à 09:29:10    

Celiphane a écrit :

Merci à tous pour vos explications !
 
 
Toutefois je me retrouve maintenant avec 2 solutions, mais laquelle choisir ?
Harkonnen m'a pointé vers le fonctionnement de Finalize qui est donc finalement la même chose plus ou moins que Dispose puisque j'y ferais le ménage.
 
Mais que faire ? Dispose ou Finalize ?
Le mieux niveau nettoyage, vitesse, ressource, c'est quoi ?
 
 
Merci encore.


fait plus confiance à Harko (chieur :o) il a bien plus d'expérience que moi en ce qui concerne .NET ;)


Message édité par MagicBuzz le 30-03-2007 à 09:29:26
Reply

Marsh Posté le 30-03-2007 à 09:50:42    

D'après ce lien : http://msdn2.microsoft.com/fr-fr/l [...] S.80).aspx
 
Je dirais en fait qu'Harko n'apporte pas une solution supplémentaire, mais des précisions.
 
Effectivement, en .NET il n'y a pas de "destructeur" à proprement parler si je pige bien l'article, mais une méthode surchargeable Finalize().
En C# et C++, on utilise une syntaxe de destructeur, mais en VB.NET et J#, qui n'ont pas de destructeurs, on doit fait un appel explicit à cette méthode.
 
C'est bien ça Harko ?
 
Toujours est-il que le "Dispose" est un "nice to have" à rajouter une fois que t'as un destructeur qui fait correctement son travail.
 
Et l'article qu'a filé Harko confirme ce que j'avais dit au début : effectivement, si on ne dit pas comment fermer un fichier au GC, il ne sait pas le faire tout seul.

Reply

Marsh Posté le 30-03-2007 à 09:50:42   

Reply

Marsh Posté le 30-03-2007 à 09:52:04    

Citation :


Remarques à l'attention des implémenteurs Object.Finalize n'a aucun effet par défaut. Il ne doit être substitué par une classe dérivée qu'en cas de nécessité, car toute récupération pendant une opération garbage collection dure bien plus longtemps si une opération Finalize doit être exécutée. Si Object contient des références à des ressources, Finalize doit être substitué par une classe dérivée afin de libérer ces ressources avant que Object soit ignoré pendant l'opération garbage collection. Un type doit implémenter Finalize s'il utilise des ressources non managées, telles que des handles de fichiers ou des connexions de bases de données, qui doivent être libérées en cas de récupération de l'objet managé qui les emploie. Pour un moyen complémentaire et plus contrôlable de détruire les ressources, consultez l'interface IDisposable. Finalize peut effectuer n'importe quelle action, y compris ressusciter (rendre à nouveau accessible) un objet qui a été nettoyé pendant une opération garbage collection. Cependant, l'objet ne peut être ressuscité qu'une seule fois. Finalize ne peut pas être appelé sur des objets ressuscités pendant une opération garbage collection.  

Reply

Marsh Posté le 30-03-2007 à 10:56:05    

Celiphane a écrit :

Merci à tous pour vos explications !
 
 
Toutefois je me retrouve maintenant avec 2 solutions, mais laquelle choisir ?
Harkonnen m'a pointé vers le fonctionnement de Finalize qui est donc finalement la même chose plus ou moins que Dispose puisque j'y ferais le ménage.
 
Mais que faire ? Dispose ou Finalize ?
Le mieux niveau nettoyage, vitesse, ressource, c'est quoi ?
 
 
Merci encore.


Les méthodes Finalize sont appelées quand le GC collecte l'objet. Il vaut mieux éviter de créer des types Finalizables, pour les raisons suivantes :
- Tu n'as aucune idée du moment auquel la méthode sera appelée, et donc du moment auquel ton objet sera libéré
- Les objets Finalizables sont plus longs à créer car ils sont placés sur la liste de Finalization du GC
- Les objets Finalizables peuvent être promus dans des générations plus anciennes (en terme de GC), ce qui sollicite davantage la mémoire
- Un objet Finalizable peut avoir une référence sur un autre objet, augmentant ainsi inutilement sa durée de vie
- Le CLR ne te garantit pas l'ordre dans lequel les méthodes Finalize seront appelées pour des objets dépendants. Si par exemple tu as un objet qui contient une référence sur un autre objet, et que le GC détecte que ces 2 objets sont collectables, il est fort possible que l'objet pointé soit libéré avant l'objet qui le pointe, pouvant aboutir à des résultats imprévisibles...
 
La méthode Finalize est appelée par le GC dans les circonstances suivantes :
- La génération 0 de la mémoire est pleine
- Appel explicit à GC.Collect()
- Le CLR décharge un domaine d'Application
- Le CLR est en cours de fermeture
 
Si tu veux faire les choses proprement, alors tu dois implémenter le pattern Dispose.  
http://haacked.com/archive/2005/11 [...] ttern.aspx

Reply

Marsh Posté le 30-03-2007 à 10:59:10    

MagicBuzz a écrit :


Effectivement, en .NET il n'y a pas de "destructeur" à proprement parler si je pige bien l'article, mais une méthode surchargeable Finalize().
En C# et C++, on utilise une syntaxe de destructeur, mais en VB.NET et J#, qui n'ont pas de destructeurs, on doit fait un appel explicit à cette méthode.
 
C'est bien ça Harko ?


Oui, sauf qu'il vaut mieux utiliser le pattern Dispose au lieu d'appeler explicitement Finalize()
 

MagicBuzz a écrit :


Et l'article qu'a filé Harko confirme ce que j'avais dit au début : effectivement, si on ne dit pas comment fermer un fichier au GC, il ne sait pas le faire tout seul.


Si, cf ma réponse au dessus :o

Reply

Marsh Posté le 30-03-2007 à 11:23:55    

Merci.

Reply

Marsh Posté le 30-03-2007 à 13:52:00    

Harkonnen a écrit :

Oui, sauf qu'il vaut mieux utiliser le pattern Dispose au lieu d'appeler explicitement Finalize()


=> Mouif, mais alors pkoi t'as mis un lien sur Finalize ? :D (/me n'a rien pigé, comme d'hab ;))
 

Harkonnen a écrit :

Si, cf ma réponse au dessus :o


=> Ouais, m'enfin ce que je voulais dire par "y sait pas faire", c'est qu'il peut aussi bien le détruire 1 ms après la destruction de l'objet appelant, tout comme il peut ne le détruire que 6 heures après.

Reply

Marsh Posté le 30-03-2007 à 14:06:48    

MagicBuzz a écrit :

=> Mouif, mais alors pkoi t'as mis un lien sur Finalize ? :D (/me n'a rien pigé, comme d'hab ;))


me suis chié dessus dans mes favoris, je voulais mettre le lien que je lui ai posté sur Dispose :whistle:

Reply

Marsh Posté le 30-03-2007 à 14:08:35    

arf :D je comprends mieux maintenant :lol:
 
(comment tu m'as trop embrouillé la tête :o genre dans le topic blabla, regarde-moi ce truc horrible que j'ai fait à cause de toi :D)


Message édité par MagicBuzz le 30-03-2007 à 14:09:26
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed