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 :

[C#] Question garbage collector


Sujet :

C#

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Points : 407
    Points
    407
    Par défaut [C#] Question garbage collector
    Bonjour à tous,
    j'ai un petit souci de mémoire dans un mes programmes.
    En je fait un readAllBytes sur un fichier et j'envoie par socket. Du coup la consommation mémoire du programme augmente, jusque la pas de souci cependant en quittant la méthode la mémoire n'est pas libérer comme cela se fait ??

    Voici mon code :

    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
            private void    Download(String Destinataire, String Commande, Byte[] Ele)
            {
                try
                {
                    String name = System.Text.Encoding.Unicode.GetString(Ele);
                    name = name.Substring(0, name.Length - 1);
                    Byte[] tab = System.IO.File.ReadAllBytes(name);
                    Int32 size = tab.Length;
                    Int32 i = 0;
                    Byte[] tosend = null;
                    FileInfo f = new FileInfo(name);
                    Byte[] tmp = System.Text.Encoding.ASCII.GetBytes(f.Name);
                    Byte[] zero = System.Text.Encoding.ASCII.GetBytes("\0");
                    long s = f.Length;
                    Byte[] siz = System.Text.Encoding.ASCII.GetBytes(Convert.ToString(s) + "\0");
                    while (i < size)
                    {
                        if (i + 65536 <= size)
                            tosend = Packet.SubByte(tab, i, i + 65536);
                        else
                            tosend = Packet.SubByte(tab, i, size);
                        tosend = Packet.Copy(zero, tosend);
                        tosend = Packet.Copy(tmp, tosend);
                        tosend = Packet.Copy(siz, tosend);
                        Byte[] packet = Packet.BuildPacket(Destinataire, Commande, tosend);
                        this.PushSend(packet);
                        i += 65536;
                    }
                }
                catch (Exception)
                {
                }
            }

    Merci d'avance !

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Parce que le garbage collector ne passe pas immédiatement... ton tableau est sorti du scope, donc il est éligible pour le garbage collector, qui libèrera la mémoire associée lors de son prochain passage. On ne peut pas prévoir exactement quand le garbage collector, il le fera quand il jugera que ça devient nécessaire

    Par contre, à mon avis ce n'est pas une bonne idée de charger tout le fichier en mémoire... tu ferais mieux de le lire au fur et à mesure de l'envoi, avec un Stream. Ca éviterait d'avoir des pics de consommation de mémoire, vu que tu n'utiliserais que N octets à la fois (N étant la taille de ton buffer)

  3. #3
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Points : 407
    Points
    407
    Par défaut
    ba hier j'ai test avec une fichier d'un go ... en local, il la mis en mémoire et 30 min plus tard il lavait toujours pas libérer...'(et 1go en mémoire ca commence à faire ... bon j'ai certe 4go mais quand même). Donc je me pose des question s'il passe toute les heures c'est pas très utile ^^

    Le temps de passage dépend-il de la quantitée de mémoire libre restant sur l'ordinateur ?

    Et comment faire pour lire que 64ko a la fois, avec un binary reader ? il y a une méthode qui fait cela ?

    Merci

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    ba hier j'ai test avec une fichier d'un go ... en local, il la mis en mémoire et 30 min plus tard il lavait toujours pas libérer...'(et 1go en mémoire ca commence à faire ... bon j'ai certe 4go mais quand même). Donc je me pose des question s'il passe toute les heures c'est pas très utile ^^

    Le temps de passage dépend-il de la quantitée de mémoire libre restant sur l'ordinateur ?
    Je sais pas quelle est la "politique" exacte de passage du GC, mais en tous cas c'est pas une question de temps. Mais effectivement c'est surprenant que pour un Go il le libère pas plus rapidement... Tu es sûr qu'il ne reste aucune référence sur ce tableau ? Ta classe Packet ne garde pas une référence dessus ?

    Sinon tu peux toujours appeler le GC explicitement après avoir enlevé toutes els références (méthode GC.Collect), mais en général on évite de faire ça car c'est assez couteux en ressources...

    Citation Envoyé par NeoKript Voir le message
    Et comment faire pour lire que 64ko a la fois, avec un binary reader ? il y a une méthode qui fait cela ?
    En général on considère que la taille de buffer optimale est plutôt de 8Ko (8192 octets).
    Pas besoin de BinaryReader (qui sert plutôt à lire des données typées à partir d'un flux binaire), un Stream est suffisant.
    Il faut juste que tu alloues un buffer, dans lequel tu charges les données en boucle :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    using (Stream stream = File.OpenRead(leFichier))
    {
        byte[] buffer = new byte[8192];
        int nBytesRead = stream.Read(buffer, 0, buffer.Length);
        while(nBytesRead > 0)
        {
            // envoyer les nBytesRead premiers octets du buffer (en général c'est le buffer entier, sauf quand tu arrives en fin de fichier)
     
            nBytesRead = stream.Read(buffer, 0, buffer.Length);
        }
    }

  5. #5
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Vis à vis du passage du GC, beaucoup de choses compte, y compris la mémoire actuellement disponible sur le système.

    Sinon, ReadAllBytes c'est mal car tu n'as absolument aucun contrôle sur la quantité de mémoire qui sera allouée. Le mieux si cette fonction ne peut être accédée que par un seul thread à la fois c'est d'avoir un buffer statique de taille fixe (8 - 32 ko) dont tu va te servir et ce sera la seule et unique allocation dans tout ton programme alors que si tu le met dans une fonction, tu aura une allocation à chaque appel sans libération immédiate.

    Après, pour éviter d'avoir une variable statique ou gérer le cas d'une fonction pouvant être appelée par plusieurs threads à la fois, il peut être efficace d'envisager l'utilisation d'un pool de buffer (genre allouer dès le départ une dizaine de byte[] de 8 ko et les récupérer quand besoin est, les remettre quand ce n'est plus nécessaire).
    (je dois avoir ça sous le coude d'ailleurs, mais ce n'est pas difficile à faire en implémentant IDisposable).

    Le but à chaque fois c'est avoir une quantité déterminée de buffers car il vaut mieux avoir 512 ko de pool alloué dès le départ et ne pas souvent s'en servir que ReadAllBytes ou un buffer à chaque appel et avoir un programme qui consomme des quantités folles de mémoire lors d'une utilisation poussée.

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    il me semble que le gc est en grande partie appelé suite à une demande de l'OS

    on peut faire le parallère avec windows qui depuis quelques années à changé de méthode de gestion de la mémoire
    tout le monde s'est plain avec l'arrivée de vista qu'il "bouffe toute la ram"
    c'est juste que y a de la ram dispo donc il met des choses dedans des fois qu'il y en ait besoin, et si c'est le cas on gagne du temps, si c'est pas le cas et qu'il faut mettre autre chose c'est pas grave on vide et on met ce qu'il y a à mettre, c'est pour ca que quand on met 4Go sur vista et qu'on lance rien il va quand meme prendre au moins 3Go

    sql server fonctionne aussi comme ca, dès qu'il lit quelque chose il le met en ram, mais ne le rend jamais meme si on ne lui demande plus
    par contre quand l'OS a besoin de place il lui dit et sql server rend alors les choses les moins utilisées

    on met de plus en plus de ram sur nos pc, si c'est pour ne pas l'utiliser ca sert à rien autant ne pas en mettre

    pour en revenir au GC, certes il se presse pas trop dans la vie, mais quand l'OS lui dit qu'il a besoin de mémoire il fait son boulot
    donc si tu as 4Go de ram, tant que windows n'en pas besoin de 5 les 1Go alloués par ton appli risque d'y rester

    après pour des traitements avec des pics de mémoire et sans solution plus propre (comme ici ne pas lire tout en une seule fois) il reste possible d'appeler le GC manuellement
    il est conseillé de faire l'appel sur un autre thread car ca consomme du temps rien qu'à l'appel
    car lors de l'appel de l'OS on peut quand même imaginé que ca prend plus de temps de libérer la mémoire au moment de la remplir avec autre chose, alors que si ca avait été vidé sur du temps libre il n'y aurait pas eut de perte

  7. #7
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    après pour des traitements avec des pics de mémoire et sans solution plus propre (comme ici ne pas lire tout en une seule fois) il reste possible d'appeler le GC manuellement
    il est conseillé de faire l'appel sur un autre thread car ca consomme du temps rien qu'à l'appel
    En fait appeler le GC sur un autre thread ne change rien, car le GC suspend tous les threads managés... j'ai appris ça récemment, je vais voir si je retrouve la référence


    EDIT:
    http://msdn.microsoft.com/en-us/magazine/bb985011.aspx
    So, when the garbage collector wants to start a collection, all threads executing managed code must be suspended. The runtime has a few different mechanisms that it uses to safely suspend threads so that a collection may be done. The reason there are multiple mechanisms is to keep threads running as long as possible and to reduce overhead as much as possible.

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    moi c'est juste que j'ai vu récemment (via un stopwatch) que gc.collect prenait plus de 500ms sur un quad core
    et à priori le reste du traitement est fait sur le thread du gc donc est indépendant de cet appel, c'était donc pour éviter ces 500ms là

  9. #9
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Points : 407
    Points
    407
    Par défaut
    Merci à tous pour vos infos, je n'était pas trop informé sur le fonctionnement du GC !

    En ne faisant pas un ReadAllByte, ca va nettement mieux moins de 5mo !

    Petite question au passage, mon programme instancie de temps en temps une fenetre WPF comment faire pour vider les ressources associée a cette fenêtre, pour le moment, je fait juste un Hide()... mais j'aimerai libérer la ressource qu'elle occupe... Comment puis-je faire ?

    Je vous remercie.

    Cordialement,
    NeoKript

  10. #10
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    Petite question au passage, mon programme instancie de temps en temps une fenetre WPF comment faire pour vider les ressources associée a cette fenêtre, pour le moment, je fait juste un Hide()... mais j'aimerai libérer la ressource qu'elle occupe... Comment puis-je faire ?
    Utilise plutôt Close que Hide si tu n'as pas l'intention de la réutiliser
    Supprime toute référence à cette fenêtre, et laisse le GC faire son boulot, il s'en occupera en temps utile

    Un conseil : n'essaie pas de gérer manuellement la mémoire, .NET n'est pas prévu pour ça. L'important c'est de ne pas entraver le fonctionnement du garbage collector, et pour ça il suffit de bien supprimer les références vers les objets que tu n'utilises plus. La plupart des fuites mémoires en .NET viennent de références non supprimées

  11. #11
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Points : 407
    Points
    407
    Par défaut
    Dac je te remercie... C'est un peu magique le .net, je suis passé au .net il y a environ un moi et demi après avoir fait 2 ans de c++ ... c'est pour ca que la mémoire je sais pas trop comment c'est gérer en cpp je faisais mes new / delete et javais pas de problèmes ^^

    Pour ma fenêtre dans une de mes classes, j'ai :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Message _message = null;
    dans ma classe et quand je veux l'utiliser je fait un new etc ...
    Pour supprimer la référence il suffit que je fasse :
    et le GC comprendra que je ne l'utilise plus ?

    Merci encore

  12. #12
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    Message _message = null; dans ma classe et quand je veux l'utiliser je fait un new etc ...
    Pour supprimer la référence il suffit que je fasse :
    this._message = null;

    et le GC comprendra que je ne l'utilise plus ?
    C'est ça. Mais encore une fois, ne t'attends pas à ce qu'il libère la mémoire instantanément...

    Si tu comprends l'anglais, regarde cette vidéo qui explique très bien comment marche le GC

  13. #13
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    en .net il n'y a pas grand chose à savoir pour la mémoire
    il faut connaitre l'interface IDisposable et à quoi elle sert
    et savoir quand mettre les références à null explicitement, car en sortie de bloc par exemple toutes les variables du bloc sont mises à null automatiquement

    j'explique ici les types managés et non managés, ainsi que using et dispose
    http://www.developpez.net/forums/d83...r/#post4810294
    dans ce post il manque la notion de finalize pour comprendre la dernière brique qui fait qu'en théorie meme si tu ne disposes rien ca sera quand supprimé un jour (peu recommandé tout de meme)

    et après y a pas plus de question que ca à se poser, c'est en grande partie automatisé

  14. #14
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2007
    Messages
    634
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2007
    Messages : 634
    Points : 407
    Points
    407
    Par défaut
    Citation Envoyé par tomlev Voir le message
    C'est ça. Mais encore une fois, ne t'attends pas à ce qu'il libère la mémoire instantanément...

    Si tu comprends l'anglais, regarde cette vidéo qui explique très bien comment marche le GC
    Merci pour la vidéos intéressant de voir comment le GC s'occupe de netoyer la stack.

    Citation Envoyé par Pol63 Voir le message
    en .net il n'y a pas grand chose à savoir pour la mémoire
    il faut connaitre l'interface IDisposable et à quoi elle sert
    et savoir quand mettre les références à null explicitement, car en sortie de bloc par exemple toutes les variables du bloc sont mises à null automatiquement

    j'explique ici les types managés et non managés, ainsi que using et dispose
    http://www.developpez.net/forums/d83...r/#post4810294
    dans ce post il manque la notion de finalize pour comprendre la dernière brique qui fait qu'en théorie meme si tu ne disposes rien ca sera quand supprimé un jour (peu recommandé tout de meme)

    et après y a pas plus de question que ca à se poser, c'est en grande partie automatisé
    Pour l'interface, je ne connaissais pas mais ca va m'être utile notamment pour la libération de la fenetre WPF.

    Merci à tous !

  15. #15
    Expert éminent
    Avatar de smyley
    Profil pro
    Inscrit en
    Juin 2003
    Messages
    6 270
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2003
    Messages : 6 270
    Points : 8 344
    Points
    8 344
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    Pour l'interface, je ne connaissais pas mais ca va m'être utile notamment pour la libération de la fenetre WPF
    Il me semble qu'on ne peut pas libérer de fenêtre WPF pour les mêmes raisons qu'on ne peut pas libérer explicitement une ressource managée.

    En WinForms chaque contrôle à un Handle et donc on doit/peut le libérer quand on en a plus besoin, et ce explicitement (Dispose/Close). En WPF tout est managé il n'y a pas de handle (sauf le handle de la fenêtre parente qui est libéré automatiquement) donc s'il n'y a plus de référence vers une fenêtre WPF on rentre dans le scénario habituel de libération par le GC.

    Il suffirait donc (en supposant que j'ai bien saisit le concept ) de ne pas avoir de référence vers une fenêtre WPF pour que le GC passe (dans plus ou moins longtemps).

  16. #16
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par NeoKript Voir le message
    Pour l'interface, je ne connaissais pas mais ca va m'être utile notamment pour la libération de la fenetre WPF.
    Hé non justement... la classe Window n'implémente pas IDisposable, c'est d'ailleurs pour ça que je n'en ai pas parlé en réponse à ta question

    Citation Envoyé par smyley Voir le message
    Il suffirait donc (en supposant que j'ai bien saisit le concept ) de ne pas avoir de référence vers une fenêtre WPF pour que le GC passe (dans plus ou moins longtemps).
    A priori c'est bien ça... ou alors j'ai rien compris moi non plus

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

Discussions similaires

  1. [JVM] Java 5 et Garbage Collector(Parralèle)
    Par ssaunois dans le forum Général Java
    Réponses: 6
    Dernier message: 28/11/2005, 23h42
  2. [JVM]Garbage collector
    Par godik dans le forum Général Java
    Réponses: 5
    Dernier message: 07/10/2005, 09h12
  3. JPanel et Garbage Collector
    Par tck-lt dans le forum Agents de placement/Fenêtres
    Réponses: 9
    Dernier message: 25/07/2005, 18h03
  4. [JVM] les objets et le Garbage collector
    Par Kurdran dans le forum Général Java
    Réponses: 7
    Dernier message: 02/06/2005, 16h57
  5. [Language]Garbage collector
    Par GETah dans le forum Langage
    Réponses: 2
    Dernier message: 23/03/2005, 15h18

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