IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Dipose et object non managé.


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Rédacteur
    Avatar de Erakis
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2003
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 523
    Par défaut Dipose et object non managé.
    Bonjour à tous,

    Qu'entend-on nous par object non managé. Si j'ai créé une DLL en MFC et que j'y fasse appel avec des fonctions du genre Start et Stop.
    Mettons que cette DLL fait que jouer un son wave dans un buffer static encapsulé dans la DLL.

    Il est impératif que la méthode Stop soit appelée lors de la destruction de l'objet, aussi elle devrait l'être si l'utilisateur appel Dispose ou encore Stop.

    De quelle façon doit-on implémenter le dispose à ce moment là ?

    Façon #1
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    public class MyMFCWrapper : IDisposable
    {
        [DllImport(DllPath, EntryPoint = "Start")]
        public static extern int MFCStart();
     
        [DllImport(DllPath, EntryPoint = "Stop")]
        public static extern int MFCStart();
     
        private bool disposed = false;
     
        public MyMFCWrapper ()
        {
           ...
        }
     
        public int Start()
        { 
           return MFCStart();
        }
     
        public int Stop()
        { 
           return MFCStop();
        }
     
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                     Stop();
                }
     
                disposed = true;
            }
        }
     
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }
    Façon #2
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
     
    public class MyMFCWrapper : IDisposable
    {
        [DllImport(DllPath, EntryPoint = "Start")]
        public static extern int MFCStart();
     
        [DllImport(DllPath, EntryPoint = "Stop")]
        public static extern int MFCStart();
     
        private bool disposed = false;
     
        public MyMFCWrapper ()
        {
           ...
        }
     
        public int Start()
        { 
           return MFCStart();
        }
     
        public int Stop()
        { 
           return MFCStop();
        }
     
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                     ....
                }
     
                Stop();
                disposed = true;
            }
        }
     
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
     
        ~ MyMFCWrapper()
        {
            Dispose(false);
        }
    }
    En fait ce qui me me mêle le plus, ce n'est pas de comprendre comment fonctionne le Dispose pattern mais plutôt de savoir QUAND exactement est-il préférable d'implémenter un finalizer (destructeur). On dit que c'est nécessaire lorsqu'on travail avec des ojbect NON-MANAGÉ. Dans ce cas-ci, cette DLL est bien un objet NON-MANAGÉ, cependant elle n'alloue pas vraiment de mémoire ?!?

    PS : D'autant plus que j'ai lu à plusieurs reprise qu'implémenter un finializer inutilement peut entraîner des pertes de performances...

    Je vous remerci d'avance pour votre aide.

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Par défaut
    Bonjour Erakis,

    Tout d'abord, concernant la necessité de la reecriture du finalizer sur des classes manipulant du non-managé, oui c'est essentiel. Imaginons, que tu oublies d'appeler un Dispose (l'appel à Dispose est fortement recommandé mais dans l'absolu, on _pourrait_ s'en passer), si le finalizer ne nettoie pas les ressources non gérés, tu vas te retrouver avec des handles qui vont se ballader (pour coller à l'exemple, si l'objet est deifinitivement detruit, qui va appeler MFCStop() ?)

    Pour l'affaire des performances, c'est vrai (et faux en meme temps ! =p). En fait, un objet qui override un finalizer survit à une collecte supplementaire : Quand un objet va etre collecté, si il a un finalizer, le GC va appelé ce dernier et donc ne pas collecté l'objet en question, pour note un objet n'a de finalizer que si il a été explicitement implementé (en gros pas de finalizer par defaut). Maintenant pour resoudre ce probleme, dans les classes manipulant du non-géré (et donc obligé de reecrire un finalizer), on utilise la methode GC.SuppressFinalize(this) qui va preciser au GC que le menage a été fait et que finalizer ou pas, pas besoin de l'appeler.

    Donc En implementant le pattern Disposable comme tu l'as fait dans le deuxieme exemple, tu es assuré que tes ressources non-gérées seront libérées, et tu n'emcombres pas le GC d'un cycle supplémentaire pour appeler un finalizer qui ne servirait à rien si Dispose() a été appelé précédemment.

    Voila, je ne sais pas si j'ai etait clair, mais l'idée à retenir :
    - Non managé = Finalizer
    - Si tu supprimes l'appel du finalizer sur un dispose explicite, tu n'auras pas de probleme de perf.

  3. #3
    Rédacteur
    Avatar de Erakis
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2003
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 523
    Par défaut
    C'est que je me suis basé sur cet acticle très bien expliqué : Code Project

    Finalization increases the cost and duration of your object's lifetime since each finalizable object must be placed on the finalization queue when it is allocated. This happens even if the finalizer is never called. This has the side effect of making the GC work harder to dispose of your object and causes it be kept alive longer.
    Ou encore ce site : Microsoft MSDN

    Remember that executing a Finalize method is costly to performance.
    Je développe un application avec Compact Frameowork. J'ai un fichier de configuration à transférer du serveur (PC) à mon Pocket PC. Ce fichier fait environ 4 Mo.

    Lorsque mon application Pocket PC est déconnecté du serveur pour une raisons X, elle doit se reconnecter au serveur et par la même occasion redemandé le fichier de 4Mo.

    Bref, lorsque le Pocket PC détecte que la connexion à été coupé, il affecte NULL à l'objet qui stock le contenu de 4Mo (une classe). Par contre, j'ai un exception OutOfMemoryException qui surviennent lorsque je ré-alloue la mémoire pour accueuillir mon objet de 4Mo.

    Je ne sais plus vraiment quoi faire...

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    547
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 547
    Par défaut
    Pour la citation, c'est en effet vrai, mais justement le fait de supprimer cette finalization si l'objet a été disposé va venir atenuer ce surcout (totalement en ce qui concerne la durée de vie, peut etre pas pour le "cout", mais ca doit rester negligeable).

    Quand tu parles de reallocation, j'imagine que tu parles d'un appel à ta dll MFC alouant de la memoire. Est ce que ca marche si le processus se passe correctement ?

    NB : je ne sais pas trop si je pourrais t'aider, n'ayant jamais utilisé le Fx compact.

  5. #5
    Rédacteur
    Avatar de Erakis
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2003
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Canada

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2003
    Messages : 523
    Par défaut
    Non le Dispose était en fait une question par pure curiosité, mais qui peut toutefois rejoint mon problème.

    J'ai retiré ma DLL (MFC) du projet pour être sur que ce n'est pas elle qui génère le problème de OutOfMemoryException. Et comme je m'y attendait, ce n'est pas elle qui cause cet exception.

    Donc, cet exception est bel et bien généré à cause d'un manque de mémoire physique sur le Pocket PC. Ce qui est emmerdant, c'est que, si cette application serait construite en MFC par exemple alors je pourrais faire ;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    delete MyBigObject;
    Et la mémoire serait alors libérée IMMÉDIATEMENT. Au lieu de ça, avec le .NET mon objet est libéré que lorsque le GC décide de le faire. Ce qui fait qu'entre le moment où j'ai libéré ma mémoire et le moment où je la ré-alloue, je peux me retrouver avec le DOUBLE de mémoire ALLOUÉ, le temps que l'ancienne soit DÉFINITIVEMENT libéré par le GC.

    Ce problème pourrait aussi bien se produire sur un PC avec le .NET Framework. Alors c'est pour cette raison que j'ai posté mon problème ici.

    Je ne sais vraiment plus comment régler ce problème, j'ai coupé par tout le moyens possible mais la...

    Si quelqu'un a des sugestions, je suis ouvert à tout !

  6. #6
    Membre confirmé
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    91
    Détails du profil
    Informations personnelles :
    Âge : 51
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Avril 2008
    Messages : 91
    Par défaut
    je sais pas si sa peut t'aider, mais en travaillant avec Microsoft.Office.Interop.Outlook j'ai été confronté a un problème de libération des objets com

    j'ai utiliser ce code la :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Marshal.releaseComObjet(InstanceObjetCom)
    InstanceObjetCom = null
    Et mon problème étais Regler

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. convertir un type non managé en type managé.
    Par poporiding dans le forum MFC
    Réponses: 6
    Dernier message: 22/05/2006, 10h49
  2. Réponses: 12
    Dernier message: 30/01/2006, 21h13
  3. [C++] Appel via paramètres non managés
    Par JulienDuSud dans le forum Framework .NET
    Réponses: 4
    Dernier message: 28/12/2005, 10h42
  4. code non managé avec interface managée ...
    Par izbad dans le forum MFC
    Réponses: 6
    Dernier message: 19/12/2005, 16h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo